Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Using the Symfony Messenger

Using the Symfony Messenger

Slides for my workshop at Dutch PHP Conference 2019.

Denis Brumann

June 06, 2019
Tweet

More Decks by Denis Brumann

Other Decks in Programming

Transcript

  1. Dutch PHP Conference 2019
    USING THE SYMFONY MESSENGER

    View Slide

  2. AGENDA
    1. Quick introduction round
    2. Setting up the project skeleton,
    while I guide you through the example code
    3. Presentation: Introduction to messenger-concepts
    4. Task 1: Introduce synchronous message processing
    5. Presentation: Transports for async processing
    6. Task 2: Pick your challenge(s)
    7. Questions

    View Slide

  3. GOALS
    Have fun
    Learn about the Messenger component
    Just 3 hours won't make you an expert, but hopefully you:
    • have a feeling whether this component is useful to you
    • maybe you get interested in message-based architecture
    Feel free to ask questions at any time.
    If you have suggestions how I can better suit your learning style,
    please let me know and I will adjust

    View Slide

  4. WHO AM I
    Denis Brumann
    Software Developer at SensioLabs Germany in Berlin
    Twitter: @dbrumann Email: [email protected]
    Personal Focus:
    • Migrating client's legacy projects
    Symfony experience:
    • started with 2.0
    • currently using 3.4 in client project
    • for private projects I try to use latest version possible

    View Slide

  5. SETTING UP THE PROJECT
    git remote add dpc2019 \
    https://github.com/dbrumann/dpc2019-workshop.git
    git fetch dpc2019
    git checkout -b develop dpc2019/master \
    --no-track

    View Slide

  6. CORE CONCEPTS
    Message
    Data Object containing all relevant data
    Message Bus
    Takes a message and delegates it to the right recipient
    Message Handler
    Takes a Message-object and handles it, i.e. processes it

    View Slide

  7. ADVANCED CONCEPTS
    Envelope
    Wrapper for a Message and contextual info (stamps)
    Stamp
    Provides context to/from a Middleware
    Middleware
    Controls the behavior of the Message Bus

    View Slide

  8. MESSAGE BUS
    interface MessageBusInterface
    {
    /**
    * Dispatches the given message.
    *
    * @param object|Envelope $message The message or the message
    * pre-wrapped in an envelope
    * @param StampInterface[] $stamps
    */
    public function dispatch($message, array $stamps = []): Envelope;
    }

    View Slide

  9. SENDING A MESSAGE
    class MyService
    {
    private $messageBus;
    public function __construct(MessageBusInterface $messageBus)
    {
    $this->messageBus = $messageBus;
    }
    public function doSomething(string $url)
    {
    $this->messageBus->dispatch(new TakeScreenshotMessage($url));
    }
    }

    View Slide

  10. SENDING A MESSAGE
    public function index(Request $request): Response
    {
    if ($request->isMethod('POST')) {
    $url = trim($request->request->get('url'));
    $this->dispatchMessage(new TakeScreenshotMessage($url));
    }
    return $this->render('screenshot.html.twig');
    }

    View Slide

  11. TASK 1
    • Install the Messenger component
    • Modify
    App\Registration\Registration::register()
    or the corresponding Controller-action
    App\Controller\RegistrationController::register()
    to use the Messenger instead
    • Create a Message-object (you can take the Form-object as a reference point)
    • Dispatch the Message using the MessageBus

    View Slide

  12. View Slide

  13. TASK 1
    • Install the Messenger component
    • Modify
    App\Registration\Registration::register()
    or the corresponding Controller-action
    App\Controller\RegistrationController::register()
    to use the Messenger instead
    • Create a Message-object (you can take the Form-object as a reference point)
    • Dispatch the Message using the MessageBus
    • Create a MessageHandler

    View Slide

  14. HANDLING MESSAGES
    class TakeScreenshotHandler implements MessageHandlerInterface
    {
    public function __invoke(TakeScreenshotMessage $message)
    {
    ...
    }
    }

    View Slide

  15. HANDLING MESSAGES
    class ScreenshotMessageSubscriber implements MessageSubscriberInterface
    {
    public static function getHandledMessages(): iterable
    {
    yield TakeScreenshotMessage::class => [
    'method' => 'takeScreenshot'
    ];
    }
    public function takeScreenshot(TakeScreenshotMessage $message)
    {
    ...
    }
    }

    View Slide

  16. View Slide

  17. https://github.com/dbrumann/dpc2019-workshop/tree/task1/sync_register
    git checkout dpc2019/task1/sync_register
    https://github.com/dbrumann/dpc2019-workshop/tree/task1/split_handler
    git checkout dpc2019/task1/split_handler

    View Slide

  18. Message
    Broker
    publish
    subscribe

    View Slide

  19. View Slide

  20. View Slide

  21. View Slide

  22. AVAILABLE TRANSPORTS
    AMQP (RabbitMQ)
    Redis
    Doctrine (using a DBAL-Connection)
    InMemory (for tests)
    Need more? Enqueue provides many more adapters

    View Slide

  23. IMPORTANT COMMANDS
    bin/console messenger:setup-transports
    bin/console messenger:consume

    View Slide

  24. PICK YOUR CHALLENGE(S)
    • Validating messages inside the MessageBus
    • Sending registration mails with Symfony Mailer
    (using async transport)
    • Creating an implicit workflow using many sync/async-handled
    messages
    • Adding capability to deal with failing messages
    • Looking into CQRS
    • Creating a CommandBus, (QueryBus), EventBus

    View Slide

  25. View Slide

  26. framework:
    messenger:
    transports:
    sync: 'sync://'
    async: '%env(MESSENGER_TRANSPORT_DSN)%'
    routing:
    # Route your messages to the transports
    App\Message\RequestRegistrationQuery: 'sync'
    App\Message\RegisterUserCommand: 'async'
    App\Message\UserRegisteredEvent: 'async'

    View Slide

  27. # default configuration
    retry_strategy:
    max_retries: 3
    delay: 1000 # delay for first retry
    multiplier: 2 # multiply delay with each try
    max_delay: 0
    # service: null
    # id for custom RetryStrategy

    View Slide

  28. framework:
    messenger:
    failure_transport: 'failed'
    transports:
    ...
    failed: 'doctrine://default?queue_name=failed'
    routing:
    ...

    View Slide

  29. bin/console messenger:failed:show
    bin/console messenger:failed:retry
    bin/console messenger:failed:remove

    View Slide

  30. $envelope = $this->dispatchMessage($form->getData());
    $token = $envelope->last(HandledStamp::class)->getResult();
    ENVELOPES & STAMPS

    View Slide

  31. Questions?

    View Slide

  32. Thank You!

    View Slide