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. 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
  2. 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
  3. 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
  4. 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
  5. 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
  6. 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
  7. 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; }
  8. 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)); } }
  9. 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'); }
  10. 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
  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 • Create a MessageHandler
  12. HANDLING MESSAGES class ScreenshotMessageSubscriber implements MessageSubscriberInterface { public static function

    getHandledMessages(): iterable { yield TakeScreenshotMessage::class => [ 'method' => 'takeScreenshot' ]; } public function takeScreenshot(TakeScreenshotMessage $message) { ... } }
  13. AVAILABLE TRANSPORTS AMQP (RabbitMQ) Redis Doctrine (using a DBAL-Connection) InMemory

    (for tests) Need more? Enqueue provides many more adapters
  14. 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
  15. 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'
  16. # 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