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.

6a1345d8e6dd15b2c78eff0c331963b1?s=128

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

  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!