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

PHP Microservice Development by the Example of a Mail Service

Max Kleucker
September 29, 2016

PHP Microservice Development by the Example of a Mail Service

This talk was given on 2016-09-29 for the PHP Usergroup Munich at Scandio.

The main topic of this talk are queue systems in various PHP frameworks and how they differ.

Max Kleucker

September 29, 2016
Tweet

More Decks by Max Kleucker

Other Decks in Programming

Transcript

  1. PHP Microservice Development by the Example of a Mail Service

    PHP UG Munich / 2016-09-28 / Max Kleucker / Scandio GmbH
  2. Why a Queue? • Substituting the Mail Delivery with a

    Mail Catcher • Additional Delivery mechanisms • Asynchronous if there are larger mail batches to be sent
  3. $connection = new AMQPStreamConnection('rabbitmq', 5672, 'guest', 'guest'); $channel = $connection->channel();

    $channel->queue_declare('send_mail', false, false, false, false); $msg = new AMQPMessage('{"property": "value"}'); $channel->basic_publish($msg, '', 'send_mail'); $channel->close(); $connection->close(); PHP Enqueue a Message
  4. $connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest'); $channel = $connection->channel();

    $channel->queue_declare('send_mail', false, false, false, false); $callback = function($msg) { echo "Received ". $msg->body. "\n"; }; $channel->basic_consume('send_mail', '', false, true, false, false, $callback); while(count($channel->callbacks)) { $channel->wait(); } PHP Process a Message
  5. Job Definition namespace App\Jobs; class SendEmail implements ShouldQueue { use

    InteractsWithQueue, Queueable, SerializesModels; protected $mail; public function __construct(Mail $mail) { $this->mail = $mail; } } Laravel
  6. $mail = new \App\Mail(); $mail->receiver = '[email protected]'; $mail->subject = 'This

    is an email!'; $mail->body = 'Moar awesome text.'; $job = new \App\Jobs\SendEmail($mail); dispatch($job->onQueue('mailqueue')); Laravel Enqueue a Message
  7. Laravel Enqueue a Message $mail = new \App\Mail(); $mail->receiver =

    '[email protected]'; $mail->subject = 'This is an email!'; $mail->body = 'Moar awesome text.'; $job = new \App\Jobs\SendEmail($mail); dispatch($job->onQueue('mailqueue'));
  8. Laravel Enqueue a Message $mail = new \App\Mail(); $mail->receiver =

    '[email protected]'; $mail->subject = 'This is an email!'; $mail->body = 'Moar awesome text.'; $job = new \App\Jobs\SendEmail($mail); dispatch($job->onQueue('mailqueue'));
  9. Laravel Enqueue a Message $mail = new \App\Mail(); $mail->receiver =

    '[email protected]'; $mail->subject = 'This is an email!'; $mail->body = 'Moar awesome text.'; $job = new \App\Jobs\SendEmail($mail); dispatch($job->onQueue('mailqueue'));
  10. { "job": "Illuminate\\Queue\\CallQueuedHandler@call", "data": { "commandName": "App\\Jobs\\SendEmail", "command": "O:18:\"App\\Jobs\\SendEmail\":5:{s: 7:\"\u0000*\u0000mail\";O:45:\"Illuminate\\Contracts\\Database\

    \ModelIdentifier\":2:{s:5:\"class\";s:8:\"App\\Mail\";s:2:\"id\";N;}s: 6:\"\u0000*\u0000job\";N;s:10:\"connection\";N;s:5:\"queue\";s: 9:\"mailqueue\";s:5:\"delay\";N;}" } } Laravel Message Payload
  11. Laravel Message Payload { "job": "Illuminate\\Queue\\CallQueuedHandler@call", "data": { "commandName": "App\\Jobs\\SendEmail",

    "command": "O:18:\"App\\Jobs\\SendEmail\":5:{s: 7:\"\u0000*\u0000mail\";O:45:\"Illuminate\\Contracts\\Database\ \ModelIdentifier\":2:{s:5:\"class\";s:8:\"App\\Mail\";s:2:\"id\";N;}s: 6:\"\u0000*\u0000job\";N;s:10:\"connection\";N;s:5:\"queue\";s: 9:\"mailqueue\";s:5:\"delay\";N;}" } }
  12. Laravel Process a Message class SendEmail implements ShouldQueue { use

    InteractsWithQueue, Queueable, SerializesModels; protected $mail; public function __construct(Mail $mail) { $this->mail = $mail; } public function handle() { $payload = $this→mail; } }
  13. class SendEmail implements ShouldQueue { use InteractsWithQueue, Queueable, SerializesModels; protected

    $mail; public function __construct(Mail $mail) { $this->mail = $mail; } public function handle() { $payload = $this->mail; } } $ php artisan queue:work Laravel Process a Job
  14. • Job-Object is used for creating and processing messages •

    Difficult if you want to use it between different applications • Data is persisted in the database, not available in the message • Low configuration overhead, easy to use Laravel Summary
  15. Symfony Symfony → RabbitMQ # app/config/config.yml old_sound_rabbit_mq: connections: default: host:

    'rabbitmq' port: 5672 user: 'guest' password: 'guest' vhost: '/' lazy: false connection_timeout: 3 read_write_timeout: 3 producers: send_mail: connection: default exchange_options: {name: 'send-mail', type: direct} queue_options: {name: 'send-mail'} consumers: send_mail: connection: default exchange_options: {name: 'send-mail', type: direct} queue_options: {name: 'send-mail'} callback: send_mail_service
  16. Symfony Enqueue a Message $mail = new Mail(); $mail->receiver =

    '[email protected]'; $mail->subject = 'This is an email!'; $mail->body = 'Moar awesome text.'; $this->get('old_sound_rabbit_mq.send_mail_producer') ->publish(serialize($mail));
  17. Symfony Enqueue a Message $mail = new Mail(); $mail->receiver =

    '[email protected]'; $mail->subject = 'This is an email!'; $mail->body = 'Moar awesome text.'; $this->get('old_sound_rabbit_mq.send_mail_producer') ->publish(serialize($mail));
  18. namespace AppBundle\Consumer; class SendMailConsumer implements ConsumerInterface { public function execute(AMQPMessage

    $msg) { $payload = $msg->getBody(); } } Symfony Process a Message • Must be registered as Service in Symfony
  19. namespace AppBundle\Consumer; class SendMailConsumer implements ConsumerInterface { public function execute(AMQPMessage

    $msg) { $payload = $msg->getBody(); } } Symfony Process a Message $ bin/console rabbitmq:consumer -w send_mail
  20. • More configuration necessary • Able to create and handle

    "bare" messages • Better suited when talking with other software Symfony Summary
  21. Queues Summary • As always: Differentiation between comfort (Laravel) and

    power (Vanilla PHP, Symfony) • Personal Opinion: Better to stay close to independent messages