Contenu connexe Similaire à PHP, RabbitMQ, and You (20) PHP, RabbitMQ, and You1. 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
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. Who has worked with
RabbitMQ in production?
Raise your hands. The only audience participation part, I promise.
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. – 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.
”
8. Event Occurs in Application
(P) Producer/Publisher - (X) Exchange - (C) Consumer
9. Message is Sent to Exchange
(P) Producer/Publisher - (X) Exchange - (C) Consumer
10. Message is Sent to Queue
(P) Producer/Publisher - (X) Exchange - (C) Consumer
Exchanges connect to Queues through Bindings
11. Message is Sent to Consumer
(P) Producer/Publisher - (X) Exchange - (C) Consumer
12. – Me, Now
“Where as a database handles your data,
a message queue handles your events.”
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. 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. 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. 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. 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();
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. 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. 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. 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();
28. Message is Sent to Exchange
(P) Producer/Publisher - (X) Exchange - (C) Consumer
34. $msg = new AMQPMessage( $message );
$channel->basic_publish($msg, '', ‘messages.new');
35. * matches one word
# matches zero or more words
A word is delineated by .
*, #, and .
44. 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
46. 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();!
47. Carrot Publisher Code
<?php
require 'vendor/autoload.php';
use CarrotPublisher;
$msg = implode(' ', array_splice($argv, 1));
(new Publisher('messages'))
->publish('message.new', $msg);
53. 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);
}
}
56. 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();
57. Publish from the web
Let’s add another consumer
Without changing existing code
58. 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();
59. 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();
60. 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();
67. 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();
68. Let’s write the email consumer
And I’ll also show you how to easily test them
69. 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();
70. 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();
76. Thank you. Review: joind.in/10558
#midwestphp #rabbitmq
Questions? Feel free to stop and ask me, email, tweet, @jasonlotito@gmail.com