Using the Symfony Messenger

Using the Symfony Messenger

Slides for my workshop at Dutch PHP Conference 2019.

6a1345d8e6dd15b2c78eff0c331963b1?s=128

Denis Brumann

June 06, 2019
Tweet

Transcript

  1. Dutch PHP Conference 2019 USING THE SYMFONY MESSENGER

  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
  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
  4. WHO AM I Denis Brumann Software Developer at SensioLabs Germany

    in Berlin Twitter: @dbrumann Email: denis.brumann@sensiolabs.de 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
  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
  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
  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
  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; }
  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)); } }
  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'); }
  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
  12. None
  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
  14. HANDLING MESSAGES class TakeScreenshotHandler implements MessageHandlerInterface { public function __invoke(TakeScreenshotMessage

    $message) { ... } }
  15. HANDLING MESSAGES class ScreenshotMessageSubscriber implements MessageSubscriberInterface { public static function

    getHandledMessages(): iterable { yield TakeScreenshotMessage::class => [ 'method' => 'takeScreenshot' ]; } public function takeScreenshot(TakeScreenshotMessage $message) { ... } }
  16. None
  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

  18. Message Broker publish subscribe

  19. None
  20. None
  21. None
  22. AVAILABLE TRANSPORTS AMQP (RabbitMQ) Redis Doctrine (using a DBAL-Connection) InMemory

    (for tests) Need more? Enqueue provides many more adapters
  23. IMPORTANT COMMANDS bin/console messenger:setup-transports bin/console messenger:consume

  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
  25. None
  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'
  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
  28. framework: messenger: failure_transport: 'failed' transports: ... failed: 'doctrine://default?queue_name=failed' routing: ...

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

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

  31. Questions?

  32. Thank You!