76
PHP, RabbitMQ, and You #mwphp14 #rabbitmq @jasonlotito MidwestPHP 2014 - RabbitMQ What will we be covering? 1. What is RabbitMQ 2. Technology Overview 3. Publishers 4. Consumers 5. Exchanges 6. Queues 7. Bindings 8. Carrot to make things easy 9. Publish events from the web 10. Multiple consumers 11. Management UI Publishing 12. Consumers Publishing

PHP, RabbitMQ, and You

Embed Size (px)

DESCRIPTION

PHP, RabbitMQ, and You talk given at MidwestPHP 2014 Video of the screens can be found here http://www.youtube.com/watch?v=Nh5oFSXEg6k This includes the videos of the sample code.

Citation preview

Page 1: PHP, RabbitMQ, and You

PHP, RabbitMQ, and You#mwphp14 #rabbitmq @jasonlotito

MidwestPHP 2014 - RabbitMQ What will we be covering?

1. What is RabbitMQ

2. Technology Overview

3. Publishers

4. Consumers

5. Exchanges

6. Queues

7. Bindings

8. Carrot to make things easy

9. Publish events from the web

10.Multiple consumers

11.Management UI Publishing

12.Consumers Publishing

Page 2: PHP, RabbitMQ, and You

PHP, RabbitMQ, and You#mwphp14 #rabbitmq @jasonlotito

Page 3: PHP, RabbitMQ, and You

Jason LotitoSenior Architect @ MeetMe

@jasonlotito.com github.com/[email protected]

!

Senior Architect means people can blame me when things don’t work as expected.

When things work, it’s because they worked around my code.

Page 4: PHP, RabbitMQ, and You

Who has worked with RabbitMQ in production?

Raise your hands. The only audience participation part, I promise.

Page 5: PHP, RabbitMQ, and You

Part 1 Crash Course In RabbitMQ

1. What is RabbitMQ

2. Technology Overview

3. Publishers

4. Consumers

5. Exchanges

6. Queues

7. Bindings

Page 6: PHP, RabbitMQ, and You

– RabbitMQ In Action*, Manning

“RabbitMQ is an open source message broker and queueing server that can be used to let

disparate applications share data via a common protocol, or to simply queue jobs for processing

by distributed workers.

Page 7: PHP, RabbitMQ, and You

Where RabbitMQ Sits(P) Producer/Publisher - (X) Exchange - (C) Consumer

Page 8: PHP, RabbitMQ, and You

Event Occurs in Application(P) Producer/Publisher - (X) Exchange - (C) Consumer

Page 9: PHP, RabbitMQ, and You

Message is Sent to Exchange(P) Producer/Publisher - (X) Exchange - (C) Consumer

Page 10: PHP, RabbitMQ, and You

Message is Sent to Queue(P) Producer/Publisher - (X) Exchange - (C) Consumer

Exchanges connect to Queues through Bindings

Page 11: PHP, RabbitMQ, and You

Message is Sent to Consumer(P) Producer/Publisher - (X) Exchange - (C) Consumer

Page 12: PHP, RabbitMQ, and You

– Me, Now

“Where as a database handles your data, a message queue handles your events.”

Page 13: PHP, RabbitMQ, and You

A database handles nouns. A message queue handles verbs.

Page 14: PHP, RabbitMQ, and You

But enough talkLet’s see some code!

Page 15: PHP, RabbitMQ, and You

composer.json"require": { "videlalvaro/php-amqplib": "2.2.*"}

Page 16: PHP, RabbitMQ, and You

We are starting with the publisher

Page 17: PHP, RabbitMQ, and You

Publisher: send.php<?php// Setup, $ php send.php whatever you want to sendrequire_once 'vendor/autoload.php'; $config = require('config.php'); use PhpAmqpLib\Connection\AMQPConnection; use PhpAmqpLib\Message\AMQPMessage; // Message Prep$connection = new AMQPConnection($config['mq']['host'], $config['mq']['port'], $config['mq']['user'], $config['mq']['pass']); $channel = $connection->channel(); $message = join(' ', array_splice($argv, 1)); $message = empty($message) ? 'Hello world!' : $message; // Publish Message$channel->basic_publish(new AMQPMessage( $message ), '', 'hello'); echo " [x] Sent '$message'\n"; $channel->close(); $connection->close();

Page 18: PHP, RabbitMQ, and You

Publisher: send.php<?php// Setup, $ php send.php whatever you want to sendrequire_once 'vendor/autoload.php'; $config = require('config.php'); use PhpAmqpLib\Connection\AMQPConnection; use PhpAmqpLib\Message\AMQPMessage; // Message Prep$connection = new AMQPConnection($config['mq']['host'], $config['mq']['port'], $config['mq']['user'], $config['mq']['pass']); $channel = $connection->channel(); $message = join(' ', array_splice($argv, 1)); $message = empty($message) ? 'Hello world!' : $message; // Publish Message$channel->basic_publish(new AMQPMessage( $message ), '', 'hello'); echo " [x] Sent '$message'\n"; $channel->close(); $connection->close();

Page 19: PHP, RabbitMQ, and You

Publisher: send.php<?php// Setup, $ php send.php whatever you want to sendrequire_once 'vendor/autoload.php'; $config = require('config.php'); use PhpAmqpLib\Connection\AMQPConnection; use PhpAmqpLib\Message\AMQPMessage; // Message Prep$connection = new AMQPConnection($config['mq']['host'], $config['mq']['port'], $config['mq']['user'], $config['mq']['pass']); $channel = $connection->channel(); $message = join(' ', array_splice($argv, 1)); $message = empty($message) ? 'Hello world!' : $message; // Publish Message$channel->basic_publish(new AMQPMessage( $message ), '', 'hello'); echo " [x] Sent '$message'\n"; $channel->close(); $connection->close();

Page 20: PHP, RabbitMQ, and You

Publisher: send.php<?php// Setup, $ php send.php whatever you want to sendrequire_once 'vendor/autoload.php'; $config = require('config.php'); use PhpAmqpLib\Connection\AMQPConnection; use PhpAmqpLib\Message\AMQPMessage; // Message Prep$connection = new AMQPConnection($config['mq']['host'], $config['mq']['port'], $config['mq']['user'], $config['mq']['pass']); $channel = $connection->channel(); $message = join(' ', array_splice($argv, 1)); $message = empty($message) ? 'Hello world!' : $message; // Publish Message$channel->basic_publish(new AMQPMessage( $message ), '', 'hello'); echo " [x] Sent '$message'\n"; $channel->close(); $connection->close();

Page 21: PHP, RabbitMQ, and You

Publisher: send.php<?php// Setup, $ php send.php whatever you want to sendrequire_once 'vendor/autoload.php'; $config = require('config.php'); use PhpAmqpLib\Connection\AMQPConnection; use PhpAmqpLib\Message\AMQPMessage; // Message Prep$connection = new AMQPConnection($config['mq']['host'], $config['mq']['port'], $config['mq']['user'], $config['mq']['pass']); $channel = $connection->channel(); $message = join(' ', array_splice($argv, 1)); $message = empty($message) ? 'Hello world!' : $message; // Publish Message$channel->basic_publish(new AMQPMessage( $message ), '', 'hello'); echo " [x] Sent '$message'\n"; $channel->close(); $connection->close();

Page 22: PHP, RabbitMQ, and You

Now we create a consumer

Page 23: PHP, RabbitMQ, and You

Consumer: receive.php<?phprequire_once 'vendor/autoload.php'; $config = require('config.php'); use PhpAmqpLib\Connection\AMQPConnection; $connection = new AMQPConnection($config['mq']['host'], $config['mq']['port'], $config['mq']['user'], $config['mq']['pass']); $channel = $connection->channel(); $channel->queue_declare('hello', false, false, false, true); echo ' [*] Waiting for messages. To exit press CTRL+C', "\n"; $handler = function($message) use($channel){ echo sprintf('Message: %s' . PHP_EOL, $message->body); }; $channel->basic_consume('hello', false, true, true, false, false, $handler); $channel->wait();

Page 24: PHP, RabbitMQ, and You

Consumer: receive.php<?phprequire_once 'vendor/autoload.php'; $config = require('config.php'); use PhpAmqpLib\Connection\AMQPConnection; $connection = new AMQPConnection($config['mq']['host'], $config['mq']['port'], $config['mq']['user'], $config['mq']['pass']); $channel = $connection->channel(); $channel->queue_declare('hello', false, false, false, true); echo ' [*] Waiting for messages. To exit press CTRL+C', "\n"; $handler = function($message) use($channel){ echo sprintf('Message: %s' . PHP_EOL, $message->body); }; $channel->basic_consume('hello', false, true, true, false, false, $handler); $channel->wait();

Page 25: PHP, RabbitMQ, and You

Consumer: receive.php<?phprequire_once 'vendor/autoload.php'; $config = require('config.php'); use PhpAmqpLib\Connection\AMQPConnection; $connection = new AMQPConnection($config['mq']['host'], $config['mq']['port'], $config['mq']['user'], $config['mq']['pass']); $channel = $connection->channel(); $channel->queue_declare('hello', false, false, false, true); echo ' [*] Waiting for messages. To exit press CTRL+C', "\n"; $handler = function($message) use($channel){ echo sprintf('Message: %s' . PHP_EOL, $message->body); }; $channel->basic_consume('hello', false, true, true, false, false, $handler); $channel->wait();

Page 26: PHP, RabbitMQ, and You

Consumer: receive.php<?phprequire_once 'vendor/autoload.php'; $config = require('config.php'); use PhpAmqpLib\Connection\AMQPConnection; $connection = new AMQPConnection($config['mq']['host'], $config['mq']['port'], $config['mq']['user'], $config['mq']['pass']); $channel = $connection->channel(); $channel->queue_declare('hello', false, false, false, true); echo ' [*] Waiting for messages. To exit press CTRL+C', "\n"; $handler = function($message) use($channel){ echo sprintf('Message: %s' . PHP_EOL, $message->body); }; $channel->basic_consume('hello', false, true, true, false, false, $handler); $channel->wait();

Page 27: PHP, RabbitMQ, and You
Page 28: PHP, RabbitMQ, and You

Message is Sent to Exchange(P) Producer/Publisher - (X) Exchange - (C) Consumer

Page 29: PHP, RabbitMQ, and You

Exchange TypesDirect, Fanout, and Topic

Page 30: PHP, RabbitMQ, and You
Page 31: PHP, RabbitMQ, and You
Page 32: PHP, RabbitMQ, and You
Page 33: PHP, RabbitMQ, and You

Queue bound to many exchanges

Page 34: PHP, RabbitMQ, and You

$msg = new AMQPMessage( $message ); $channel->basic_publish($msg, '', ‘messages.new');

Page 35: PHP, RabbitMQ, and You

* matches one word # matches zero or more words

A word is delineated by .

*, #, and .

Page 36: PHP, RabbitMQ, and You

*.new messages.*

NOT *.messages.*

messages.new matches

Page 37: PHP, RabbitMQ, and You

NOT spam.* spam.*.* spam.#

spam.message.new matches

Page 38: PHP, RabbitMQ, and You

Now Let’s Create an Exchange and a Queue

Page 39: PHP, RabbitMQ, and You

Using the Management UIrabbitmq-plugins enable rabbitmq_management

http://localhost:15672

Page 40: PHP, RabbitMQ, and You
Page 41: PHP, RabbitMQ, and You
Page 42: PHP, RabbitMQ, and You

We’ve Created EverythingPublishers, Exchanges, Bindings, Queues, and Consumers

Page 43: PHP, RabbitMQ, and You

So what can we do with this?

Page 44: PHP, RabbitMQ, and You

Part 2 PHP & RabbitMQ Together

1. Carrot to make things easy

2. Publish events from the web

3. Multiple consumers

4. Management UI Publishing

5. Consumers Publishing

Page 45: PHP, RabbitMQ, and You

Carrotgithub.com/jasonlotito/Carrot

Page 46: PHP, RabbitMQ, and You

Carrot Consumer Code<?phprequire_once 'vendor/autoload.php'; use Carrot\Consumer; $queue = 'new_messages'; $handler = function($msg){ echo $msg, PHP_EOL; return true; }; (new Consumer())->listenTo($queue, $handler) ->listenAndWait(); !

Page 47: PHP, RabbitMQ, and You

Carrot Publisher Code

<?phprequire 'vendor/autoload.php'; use Carrot\Publisher; $msg = implode(' ', array_splice($argv, 1)); (new Publisher('messages')) ->publish('message.new', $msg);

Page 48: PHP, RabbitMQ, and You
Page 49: PHP, RabbitMQ, and You

Make publishing easy

Page 50: PHP, RabbitMQ, and You

Make consuming easier

Page 51: PHP, RabbitMQ, and You

github.com/jasonlotito/midwest-rabbitmq/tree/carrot

Page 52: PHP, RabbitMQ, and You

Adding the Web

Page 53: PHP, RabbitMQ, and You

Publisher$publisher = new Publisher('messages'); $sendCount = (int) (isset($_POST['simulatedMessageCount']) ? $_POST['simulatedMessageCount'] : 1); for($x = 0; $x<$sendCount; $x++){ if(isset($_POST['simulateWork'])) { usleep(500000); $msg = ['comment' => $_POST['comment'] . " $x"]; $publisher->eventuallyPublish('message.new', $msg); } else { $msg = ['comment' => $_POST['comment'] . " $x"]; $publisher->publish('message.new', $msg); } }

Page 54: PHP, RabbitMQ, and You

Let’s use the written Carrot Consumer Code

Page 55: PHP, RabbitMQ, and You
Page 56: PHP, RabbitMQ, and You

batch_basic_publishpublic function eventuallyPublish($routingKey, $message) { $msg = $this->buildMessage($message); $channel = $this->getChannel(); $channel->batch_basic_publish($msg, $this->exchange, $routingKey); $this->registerShutdownHandler(); } public function finallyPublish() { if ($this->doBatchPublish) { $this->doBatchPublish = false; $this->getChannel()->publish_batch(); } } !// register finallyPublish private function registerShutdownHandler();

Page 57: PHP, RabbitMQ, and You

Publish from the web Let’s add another consumer

Without changing existing code

Page 58: PHP, RabbitMQ, and You

send text messages

$queueName = 'messages_for_nexmo'; (new Consumer()) ->bind($queueName, 'messages', 'message.new') ->listenTo($queueName, function($msg) use($key, $secret, $phoneNumber) { $msg = json_decode($msg); $urlString = 'https://rest.nexmo.com/sms/json?api_key=%s&api_secret=%s' . '&from=17088568489&to=%s&text=%s'; $preparedMessage = urlencode($msg->comment); $url = sprintf($urlString, $key, $secret, $phoneNumber, $preparedMessage); $res = file_get_contents($url); $result = json_decode($res); $messageResult = $result->messages[0]; echo "Message Result: " . ($messageResult->status === '0' ? 'Message Sent' : 'Message not sent') . PHP_EOL; return $messageResult->status === '0'; })->listenAndWait();

Page 59: PHP, RabbitMQ, and You

send text messages

$queueName = 'messages_for_nexmo'; (new Consumer()) ->bind($queueName, 'messages', 'message.new') ->listenTo($queueName, function($msg) use($key, $secret, $phoneNumber) { $msg = json_decode($msg); $urlString = 'https://rest.nexmo.com/sms/json?api_key=%s&api_secret=%s' . '&from=17088568489&to=%s&text=%s'; $preparedMessage = urlencode($msg->comment); $url = sprintf($urlString, $key, $secret, $phoneNumber, $preparedMessage); $res = file_get_contents($url); $result = json_decode($res); $messageResult = $result->messages[0]; echo "Message Result: " . ($messageResult->status === '0' ? 'Message Sent' : 'Message not sent') . PHP_EOL; return $messageResult->status === '0'; })->listenAndWait();

Page 60: PHP, RabbitMQ, and You

send text messages

$queueName = 'messages_for_nexmo'; (new Consumer()) ->bind($queueName, 'messages', 'message.new') ->listenTo($queueName, function($msg) use($key, $secret, $phoneNumber) { $msg = json_decode($msg); $urlString = 'https://rest.nexmo.com/sms/json?api_key=%s&api_secret=%s' . '&from=17088568489&to=%s&text=%s'; $preparedMessage = urlencode($msg->comment); $url = sprintf($urlString, $key, $secret, $phoneNumber, $preparedMessage); $res = file_get_contents($url); $result = json_decode($res); $messageResult = $result->messages[0]; echo "Message Result: " . ($messageResult->status === '0' ? 'Message Sent' : 'Message not sent') . PHP_EOL; return $messageResult->status === '0'; })->listenAndWait();

Page 61: PHP, RabbitMQ, and You

Both queues get the message

Page 62: PHP, RabbitMQ, and You
Page 63: PHP, RabbitMQ, and You

Let’s add another layer

Page 64: PHP, RabbitMQ, and You

Yo dawg, let’s have a consumer publish

Page 65: PHP, RabbitMQ, and You

Send an email After the text message

Page 66: PHP, RabbitMQ, and You

Create a new Exchange

Page 67: PHP, RabbitMQ, and You

Update text message consumer

$publisher = new Publisher('sms'); (new Consumer()) ->bind($queueName, 'messages', 'message.new') ->listenTo($queueName, function($msg) use($key, $secret, $phoneNumber, $publisher) { // existing code $successful = $messageResult->status === '0'; if ($successful) { $publisher->publish(‘sms.sent', ['message' => $msg->comment]); } return $successful; })->listenAndWait();

Page 68: PHP, RabbitMQ, and You

Let’s write the email consumerAnd I’ll also show you how to easily test them

Page 69: PHP, RabbitMQ, and You

Email Consumer

(new Consumer()) ->bind('send_email', 'emails', '*.send') ->bind('send_email', 'sms', '*.sent') ->listenTo('send_email', function($message){ $msg = json_decode($message); mail('[email protected]', 'MidwestPHP RabbitMQ Talk', $msg->message); echo 'Message sent: ' . $msg->message . PHP_EOL; return true; })->listenAndWait();

Page 70: PHP, RabbitMQ, and You

Email consumer

(new Consumer()) ->bind('send_email', 'emails', '*.send') ->bind('send_email', 'sms', '*.sent') ->listenTo('send_email', function($message){ $msg = json_decode($message); mail('[email protected]', 'MidwestPHP RabbitMQ Talk', $msg->message); echo 'Message sent: ' . $msg->message . PHP_EOL; return true; })->listenAndWait();

Page 71: PHP, RabbitMQ, and You
Page 72: PHP, RabbitMQ, and You

Now, let’s see it from the beginning

Page 73: PHP, RabbitMQ, and You
Page 74: PHP, RabbitMQ, and You

rabbitmq.org

Page 75: PHP, RabbitMQ, and You
Page 76: PHP, RabbitMQ, and You

Thank you. Review: joind.in/10558#midwestphp #rabbitmq

Questions? Feel free to stop and ask me, email, tweet, @[email protected]