PHP, RabbitMQ, and You
Upcoming SlideShare
Loading in...5
×
 

PHP, RabbitMQ, and You

on

  • 1,245 views

PHP, RabbitMQ, and You talk given at MidwestPHP 2014 ...

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.

Statistics

Views

Total Views
1,245
Views on SlideShare
1,245
Embed Views
0

Actions

Likes
4
Downloads
14
Comments
1

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel

11 of 1

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
  • How can I process callback in OOP, not only function but method of an object? I'm newbie in rabbitmq, esp amqp.

    Thanks
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    PHP, RabbitMQ, and You PHP, RabbitMQ, and You Presentation Transcript

    • 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 #mwphp14 #rabbitmq @jasonlotito
    • 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.
    • Who has worked with RabbitMQ in production? Raise your hands. The only audience participation part, I promise.
    • Part 1 Crash Course In RabbitMQ 1. What is RabbitMQ 2. Technology Overview 3. Publishers 4. Consumers 5. Exchanges 6. Queues 7. Bindings
    • – 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. ”
    • Where RabbitMQ Sits (P) Producer/Publisher - (X) Exchange - (C) Consumer
    • Event Occurs in Application (P) Producer/Publisher - (X) Exchange - (C) Consumer
    • Message is Sent to Exchange (P) Producer/Publisher - (X) Exchange - (C) Consumer
    • Message is Sent to Queue (P) Producer/Publisher - (X) Exchange - (C) Consumer Exchanges connect to Queues through Bindings
    • Message is Sent to Consumer (P) Producer/Publisher - (X) Exchange - (C) Consumer
    • – Me, Now “Where as a database handles your data, a message queue handles your events.”
    • A database handles nouns. A message queue handles verbs.
    • But enough talk Let’s see some code!
    • composer.json "require": {
 "videlalvaro/php-amqplib": "2.2.*"
 }
    • We are starting with the publisher
    • 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();

    • 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();

    • 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();

    • 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();

    • 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();

    • Now we create a consumer
    • 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();
    • 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();
    • 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();
    • 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();
    • Message is Sent to Exchange (P) Producer/Publisher - (X) Exchange - (C) Consumer
    • Exchange Types Direct, Fanout, and Topic
    • Queue bound to many exchanges
    • $msg = new AMQPMessage( $message );
 $channel->basic_publish($msg, '', ‘messages.new');
    • * matches one word # matches zero or more words A word is delineated by . *, #, and .
    • *.new messages.* NOT *.messages.* messages.new matches
    • NOT spam.* spam.*.* spam.# spam.message.new matches
    • Now Let’s Create an Exchange and a Queue
    • Using the Management UI rabbitmq-plugins enable rabbitmq_management http://localhost:15672
    • We’ve Created Everything Publishers, Exchanges, Bindings, Queues, and Consumers
    • So what can we do with this?
    • 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
    • Carrot github.com/jasonlotito/Carrot
    • 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();!
    • Carrot Publisher Code <?php
 require 'vendor/autoload.php';
 
 use CarrotPublisher;
 
 $msg = implode(' ', array_splice($argv, 1));
 (new Publisher('messages'))
 ->publish('message.new', $msg);
    • Make publishing easy
    • Make consuming easier
    • github.com/jasonlotito/ midwest-rabbitmq/tree/carrot
    • Adding the Web
    • 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);
 }
 }
    • Let’s use the written Carrot Consumer Code
    • 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();

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

    • 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();

    • 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();

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

    • Let’s write the email consumer And I’ll also show you how to easily test them
    • 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();
    • 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();
    • Now, let’s see it from the beginning
    • rabbitmq.org
    • Thank you. Review: joind.in/10558 #midwestphp #rabbitmq Questions? Feel free to stop and ask me, email, tweet, @jasonlotito@gmail.com