PHP, RabbitMQ, and You

3,848 views

Published on

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.

Published in: Technology
1 Comment
9 Likes
Statistics
Notes
  • How can I process callback in OOP, not only function but method of an object? I'm newbie in rabbitmq, esp amqp.

    Thanks
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total views
3,848
On SlideShare
0
From Embeds
0
Number of Embeds
26
Actions
Shares
0
Downloads
75
Comments
1
Likes
9
Embeds 0
No embeds

No notes for slide

PHP, RabbitMQ, and You

  1. 1. 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
  2. 2. PHP, RabbitMQ, and You #mwphp14 #rabbitmq @jasonlotito
  3. 3. Jason Lotito Senior Architect @ MeetMe @jasonlotito.com github.com/jasonlotito@gmail.com ! 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.
  4. 4. Who has worked with RabbitMQ in production? Raise your hands. The only audience participation part, I promise.
  5. 5. Part 1 Crash Course In RabbitMQ 1. What is RabbitMQ 2. Technology Overview 3. Publishers 4. Consumers 5. Exchanges 6. Queues 7. Bindings
  6. 6. – 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. ”
  7. 7. Where RabbitMQ Sits (P) Producer/Publisher - (X) Exchange - (C) Consumer
  8. 8. Event Occurs in Application (P) Producer/Publisher - (X) Exchange - (C) Consumer
  9. 9. Message is Sent to Exchange (P) Producer/Publisher - (X) Exchange - (C) Consumer
  10. 10. Message is Sent to Queue (P) Producer/Publisher - (X) Exchange - (C) Consumer Exchanges connect to Queues through Bindings
  11. 11. Message is Sent to Consumer (P) Producer/Publisher - (X) Exchange - (C) Consumer
  12. 12. – Me, Now “Where as a database handles your data, a message queue handles your events.”
  13. 13. A database handles nouns. A message queue handles verbs.
  14. 14. But enough talk Let’s see some code!
  15. 15. composer.json "require": {
 "videlalvaro/php-amqplib": "2.2.*"
 }
  16. 16. We are starting with the publisher
  17. 17. Publisher: send.php <?php
 // Setup, $ php send.php whatever you want to send
 require_once 'vendor/autoload.php';
 $config = require('config.php');
 use PhpAmqpLibConnectionAMQPConnection;
 use PhpAmqpLibMessageAMQPMessage;
 
 // 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();

  18. 18. Publisher: send.php <?php
 // Setup, $ php send.php whatever you want to send
 require_once 'vendor/autoload.php';
 $config = require('config.php');
 use PhpAmqpLibConnectionAMQPConnection;
 use PhpAmqpLibMessageAMQPMessage;
 
 // 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();

  19. 19. Publisher: send.php <?php
 // Setup, $ php send.php whatever you want to send
 require_once 'vendor/autoload.php';
 $config = require('config.php');
 use PhpAmqpLibConnectionAMQPConnection;
 use PhpAmqpLibMessageAMQPMessage;
 
 // 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();

  20. 20. Publisher: send.php <?php
 // Setup, $ php send.php whatever you want to send
 require_once 'vendor/autoload.php';
 $config = require('config.php');
 use PhpAmqpLibConnectionAMQPConnection;
 use PhpAmqpLibMessageAMQPMessage;
 
 // 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();

  21. 21. Publisher: send.php <?php
 // Setup, $ php send.php whatever you want to send
 require_once 'vendor/autoload.php';
 $config = require('config.php');
 use PhpAmqpLibConnectionAMQPConnection;
 use PhpAmqpLibMessageAMQPMessage;
 
 // 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();

  22. 22. Now we create a consumer
  23. 23. Consumer: receive.php <?php
 
 require_once 'vendor/autoload.php';
 $config = require('config.php');
 use PhpAmqpLibConnectionAMQPConnection;
 
 $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();
  24. 24. Consumer: receive.php <?php
 
 require_once 'vendor/autoload.php';
 $config = require('config.php');
 use PhpAmqpLibConnectionAMQPConnection;
 
 $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();
  25. 25. Consumer: receive.php <?php
 
 require_once 'vendor/autoload.php';
 $config = require('config.php');
 use PhpAmqpLibConnectionAMQPConnection;
 
 $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();
  26. 26. Consumer: receive.php <?php
 
 require_once 'vendor/autoload.php';
 $config = require('config.php');
 use PhpAmqpLibConnectionAMQPConnection;
 
 $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();
  27. 27. Message is Sent to Exchange (P) Producer/Publisher - (X) Exchange - (C) Consumer
  28. 28. Exchange Types Direct, Fanout, and Topic
  29. 29. Queue bound to many exchanges
  30. 30. $msg = new AMQPMessage( $message );
 $channel->basic_publish($msg, '', ‘messages.new');
  31. 31. * matches one word # matches zero or more words A word is delineated by . *, #, and .
  32. 32. *.new messages.* NOT *.messages.* messages.new matches
  33. 33. NOT spam.* spam.*.* spam.# spam.message.new matches
  34. 34. Now Let’s Create an Exchange and a Queue
  35. 35. Using the Management UI rabbitmq-plugins enable rabbitmq_management http://localhost:15672
  36. 36. We’ve Created Everything Publishers, Exchanges, Bindings, Queues, and Consumers
  37. 37. So what can we do with this?
  38. 38. 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
  39. 39. Carrot github.com/jasonlotito/Carrot
  40. 40. Carrot Consumer Code <?php
 require_once 'vendor/autoload.php';
 
 use CarrotConsumer; $queue = 'new_messages';
 $handler = function($msg){
 echo $msg, PHP_EOL;
 return true;
 }; 
 (new Consumer())->listenTo($queue, $handler)
 ->listenAndWait();!
  41. 41. Carrot Publisher Code <?php
 require 'vendor/autoload.php';
 
 use CarrotPublisher;
 
 $msg = implode(' ', array_splice($argv, 1));
 (new Publisher('messages'))
 ->publish('message.new', $msg);
  42. 42. Make publishing easy
  43. 43. Make consuming easier
  44. 44. github.com/jasonlotito/ midwest-rabbitmq/tree/carrot
  45. 45. Adding the Web
  46. 46. 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);
 }
 }
  47. 47. Let’s use the written Carrot Consumer Code
  48. 48. batch_basic_publish public 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();

  49. 49. Publish from the web Let’s add another consumer Without changing existing code
  50. 50. 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();

  51. 51. 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();

  52. 52. 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();

  53. 53. Both queues get the message
  54. 54. Let’s add another layer
  55. 55. Yo dawg, let’s have a consumer publish
  56. 56. Send an email After the text message
  57. 57. Create a new Exchange
  58. 58. 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();

  59. 59. Let’s write the email consumer And I’ll also show you how to easily test them
  60. 60. Email Consumer (new Consumer())
 ->bind('send_email', 'emails', '*.send')
 ->bind('send_email', 'sms', '*.sent')
 ->listenTo('send_email', function($message){
 $msg = json_decode($message);
 mail('jasonlotito@gmail.com', 'MidwestPHP RabbitMQ Talk', $msg->message);
 echo 'Message sent: ' . $msg->message . PHP_EOL;
 return true;
 })->listenAndWait();
  61. 61. Email consumer (new Consumer())
 ->bind('send_email', 'emails', '*.send')
 ->bind('send_email', 'sms', '*.sent')
 ->listenTo('send_email', function($message){
 $msg = json_decode($message);
 mail('jasonlotito@gmail.com', 'MidwestPHP RabbitMQ Talk', $msg->message);
 echo 'Message sent: ' . $msg->message . PHP_EOL;
 return true;
 })->listenAndWait();
  62. 62. Now, let’s see it from the beginning
  63. 63. rabbitmq.org
  64. 64. Thank you. Review: joind.in/10558 #midwestphp #rabbitmq Questions? Feel free to stop and ask me, email, tweet, @jasonlotito@gmail.com

×