├── .gitignore ├── LICENSE.md ├── README.md ├── configs ├── haproxy │ ├── haproxy.cfg.local_cluster │ └── haproxy.cfg.slb_warren └── rabbitmq │ └── rabbitmq.config.shovel ├── csharp └── appendix-a │ ├── AlertingServerConsumer │ ├── AlertingServerConsumer.csproj │ ├── AlertingServerConsumer.sln │ └── alerting_server_consumer.cs │ ├── AlertingServerProducer │ ├── AlertingServerProducer.csproj │ ├── AlertingServerProducer.sln │ └── alerting_server_producer.cs │ ├── HelloWorldConsumer │ ├── HelloWorldConsumer.csproj │ ├── HelloWorldConsumer.sln │ └── hello_world_consumer.cs │ └── HelloWorldProducer │ ├── HelloWorldProducer.csproj │ ├── HelloWorldProducer.sln │ └── hello_world_producer.cs ├── erlang └── chapter-12 │ └── rabbitmq-recent-history-exchange │ ├── .gitignore │ ├── LICENSE.md │ ├── Makefile │ ├── README.md │ ├── package.mk │ └── src │ ├── rabbit_exchange_type_recent_history.erl │ └── rabbitmq_recent_history_exchange.app.src ├── java └── appendix-a │ ├── Client.java │ └── Server.java ├── php ├── chapter-1 │ ├── hello-world-consumer.php │ └── hello-world-producer.php ├── chapter-11 │ └── ssl_connection.php ├── chapter-12 │ ├── recent_history_consumer.php │ └── recent_history_producer.php ├── chapter-3 │ └── rabbitmqctl-examples.php ├── chapter-4 │ ├── listing-4.10.php │ ├── listing-4.11.php │ ├── listing-4.7.php │ ├── listing-4.8.php │ └── listing-4.9.php └── config │ └── config.php ├── pika-0.9.6.tar.bz2 ├── python ├── chapter-10 │ ├── amqp_ping_check.py │ ├── amqp_queue_count_check.py │ ├── api_ping_check.py │ ├── api_queue_count_check.py │ ├── cluster_health_check.py │ ├── nagios_check.py │ └── queue_config_check.py ├── chapter-2 │ ├── hello_world_consumer.py │ ├── hello_world_producer.py │ ├── hello_world_producer_pubconfirm.py │ └── hello_world_producer_tx.py ├── chapter-4 │ ├── alert_consumer.py │ ├── alert_producer.py │ ├── rpc_client.py │ └── rpc_server.py ├── chapter-5 │ ├── hello_world_mirrored_queue_consumer.py │ └── hello_world_mirrored_queue_consumer_selective_nodes.py ├── chapter-6 │ ├── cluster_test_consumer.py │ └── cluster_test_producer.py ├── chapter-7 │ ├── shovel_consumer.py │ └── shovel_producer.py └── chapter-9 │ ├── node_lister.py │ ├── queue_stats.py │ ├── user_manager.py │ └── user_vhost_manager.py └── ruby ├── .gitignore ├── Gemfile └── chapter-2 ├── hello_world_consumer.rb └── hello_world_producer.rb /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | *.suo 4 | *.csproj.user 5 | *.class 6 | *.jar -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2011, Jason J. W. Williams, Alvaro Videla 2 | All rights reserved. 3 | 4 | Distributed under the BSD License. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 9 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RabbitMQ in Action Examples # 2 | 3 | 4 | ## Requirements ## 5 | 6 | ### Python Examples ### 7 | 8 | * Python 2.6 or newer 9 | * [Pika](https://github.com/pika/pika) 10 | 11 | ### PHP Examples ### 12 | * The examples where tested with PHP 5.3 13 | * [php-amqplib](http://github.com/tnc/php-amqplib) 14 | 15 | ### Ruby Examples ### 16 | * Ruby 1.8.7 or 1.9.2. JRuby and Rubinius are supported. 17 | * [amqp gem](http://github.com/ruby-amqp/amqp) 0.8.0.RC12 or later. See [Getting Started Guide](http://bit.ly/jcuACj) for installation instructions. 18 | 19 | ## Running the Examples: Python ## 20 | 21 | ### 3.2.2 Alerting Framework ### 22 | 23 | _Requirements:_ 24 | 25 | * RabbitMQ server (2.6.1 or later) running on localhost. 26 | * RabbitMQ user needed: 27 | * Username: alert\_user 28 | * Password: alertme 29 | * Permissions: read,write,config 30 | 31 | _Running the Consumer:_ __python 3.2.2\_alert\_consumer.py__ 32 | 33 | _Running the Producer:_ __python 3.2.2\_alert\_producer.py -r ROUTING\_KEY -m MESSAGE__ 34 | 35 | 36 | ### 3.3.3 RPC Example ### 37 | 38 | _Requirements:_ 39 | 40 | * RabbitMQ server (2.6.1 or later) running on localhost. 41 | * RabbitMQ user needed: 42 | * Username: rpc\_user 43 | * Password: rpcme 44 | * Permissions: read,write,config 45 | 46 | 47 | _Running the Server:_ __python 3.3.3\_rpc\_server.py__ 48 | _Running the Client:_ __python 3.3.3\_rpc\_server.py__ 49 | 50 | ## Running the Examples: PHP ## 51 | 52 | * RabbitMQ server (2.6.1 or later) running on localhost. 53 | * RabbitMQ user needed: 54 | * Username: guest 55 | * Password: guest 56 | 57 | To run the PHP scripts simply do: 58 | 59 | php script_name.php 60 | 61 | ## Running the Examples: Ruby ## 62 | 63 | * RabbitMQ server (2.6.1 or later) running on localhost. 64 | * RabbitMQ user needed: 65 | * Username: guest 66 | * Password: guest 67 | 68 | To run examples do 69 | 70 | ruby chapter-1/hello_world_consumer.rb 71 | 72 | and so on. Or, if you use Bundler 73 | 74 | bundle exec ruby chapter-1/hello_world_consumer.rb 75 | 76 | ## Note to contributors ## 77 | 78 | **BY CONTRIBUTING TO THE RABBITMQ IN ACTION SOURCE CODE REPOSITORY YOU AGREE TO LICENSE YOUR CONTRIBUTION UNDER THE TERMS OF THE BSD LICENSE AS SPECIFIED IN THE 'LICENSE.md' FILE IN THIS DIRECTORY.** 79 | 80 | -------------------------------------------------------------------------------- /configs/haproxy/haproxy.cfg.local_cluster: -------------------------------------------------------------------------------- 1 | # HAProxy Config for Local RabbitMQ Cluster 2 | 3 | #/(hap.0) Logging options 4 | global 5 | log 127.0.0.1 local0 info 6 | maxconn 4096 7 | stats socket /tmp/haproxy.socket uid haproxy mode 770 level admin 8 | daemon 9 | 10 | #/(hap.1) Load balancing defaults 11 | defaults 12 | log global 13 | mode tcp 14 | option tcplog 15 | option dontlognull 16 | retries 3 17 | option redispatch 18 | maxconn 2000 19 | timeout connect 5s 20 | timeout client 120s 21 | timeout server 120s 22 | 23 | #/(hap.2) Front-end IP for our consumers and producers 24 | 25 | 26 | 27 | listen rabbitmq_local_cluster 127.0.0.1:5670 28 | #/(hap.3) Load balancing options 29 | mode tcp 30 | balance roundrobin 31 | #/(hap.4) Cluster nodes HAProxy will be load balancing. 32 | 33 | 34 | 35 | server rabbit 127.0.0.1:5672 check inter 5000 rise 2 fall 3 36 | server rabbit_1 127.0.0.1:5673 check inter 5000 rise 2 fall 3 37 | server rabbit_2 127.0.0.1:5674 check inter 5000 rise 2 fall 3 38 | 39 | #/(hap.5) Statistics page 40 | listen private_monitoring :8100 41 | mode http 42 | option httplog 43 | stats enable 44 | stats uri /stats 45 | stats refresh 5s 46 | -------------------------------------------------------------------------------- /configs/haproxy/haproxy.cfg.slb_warren: -------------------------------------------------------------------------------- 1 | # HAProxy Config for Local RabbitMQ SLB Warren 2 | 3 | #/(haw.0) Logging options 4 | global 5 | log 127.0.0.1 local0 info 6 | maxconn 4096 7 | stats socket /tmp/haproxy_2.socket uid haproxy mode 770 level admin 8 | daemon 9 | 10 | #/(haw.1) Load balancing defaults 11 | defaults 12 | log global 13 | mode tcp 14 | option tcplog 15 | option dontlognull 16 | retries 3 17 | option redispatch 18 | maxconn 2000 19 | timeout connect 5s 20 | timeout client 120s 21 | timeout server 120s 22 | 23 | #/(haw.2) Front-end IP for our consumers and producers 24 | 25 | 26 | 27 | listen rabbitmq_local_cluster 127.0.0.1:5680 28 | #/(haw.3) Load balancing options 29 | mode tcp 30 | balance roundrobin 31 | #/(haw.4) Active node 32 | server rabbit_a 127.0.0.1:5675 check inter 5000 rise 2 fall 3 33 | #/(haw.5) Backup node 34 | server rabbit_b 127.0.0.1:5676 backup check inter 5000 rise 2 fall 3 35 | 36 | #/(haw.6) Statistics page 37 | listen private_monitoring :8101 38 | mode http 39 | option httplog 40 | stats enable 41 | stats uri /stats 42 | stats refresh 5s 43 | -------------------------------------------------------------------------------- /configs/rabbitmq/rabbitmq.config.shovel: -------------------------------------------------------------------------------- 1 | [ 2 | {mnesia, [{dump_log_write_threshold, 100} 3 | ]}, 4 | {rabbit, [{vm_memory_high_watermark, 0.4} 5 | ]}, 6 | {rabbitmq_shovel, 7 | [{shovels, 8 | [{avocado_order_shovel, 9 | [{sources, [{broker, "amqp://guest:guest@localhost:5675/"}, 10 | {declarations, 11 | [{'queue.declare', 12 | [{queue, <<"backup_orders">>}, 13 | durable]}, 14 | {'exchange.declare', 15 | [{exchange, <<"incoming_orders">>}, 16 | {type, <<"direct">>}, 17 | durable]}, 18 | {'queue.bind', 19 | [{exchange, <<"incoming_orders">>}, 20 | {queue, <<"backup_orders">>}, 21 | {routing_key, <<"warehouse">>}]} 22 | ]}]}, 23 | {destinations, [{broker, "amqp://guest:guest@localhost:5676"}, 24 | {declarations, 25 | [{'queue.declare', 26 | [{queue, <<"warehouse_carpinteria">>}, 27 | durable]}, 28 | {'exchange.declare', 29 | [{exchange, <<"incoming_orders">>}, 30 | {type, <<"direct">>}, 31 | durable]}, 32 | {'queue.bind', 33 | [{exchange, <<"incoming_orders">>}, 34 | {queue, <<"warehouse_carpinteria">>}, 35 | {routing_key, <<"warehouse">>}]} 36 | ]}]}, 37 | {queue, <<"backup_orders">>}, 38 | {ack_mode, on_confirm}, 39 | {publish_properties, [{delivery_mode, 2}]}, 40 | {publish_fields, [{exchange, <<"incoming_orders">>}, 41 | {routing_key, <<"warehouse">>}]}, 42 | {reconnect_delay, 5} 43 | ]} 44 | ] 45 | }] 46 | } 47 | ]. 48 | 49 | 50 | -------------------------------------------------------------------------------- /csharp/appendix-a/AlertingServerConsumer/AlertingServerConsumer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {AA0F666B-460C-41AC-B212-C77AF9362224} 9 | Exe 10 | Properties 11 | Project1 12 | AlertingServerConsumer 13 | v4.0 14 | Client 15 | 512 16 | 17 | 18 | x86 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | x86 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | C:\Program Files\JSON.NET\Bin\Net35\Newtonsoft.Json.dll 39 | 40 | 41 | False 42 | C:\Program Files\RabbitMQ\DotNetClient\bin\RabbitMQ.Client.dll 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 57 | -------------------------------------------------------------------------------- /csharp/appendix-a/AlertingServerConsumer/AlertingServerConsumer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual C# Express 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AlertingServerConsumer", "AlertingServerConsumer.csproj", "{AA0F666B-460C-41AC-B212-C77AF9362224}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|x86 = Debug|x86 9 | Release|x86 = Release|x86 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {AA0F666B-460C-41AC-B212-C77AF9362224}.Debug|x86.ActiveCfg = Debug|x86 13 | {AA0F666B-460C-41AC-B212-C77AF9362224}.Debug|x86.Build.0 = Debug|x86 14 | {AA0F666B-460C-41AC-B212-C77AF9362224}.Release|x86.ActiveCfg = Release|x86 15 | {AA0F666B-460C-41AC-B212-C77AF9362224}.Release|x86.Build.0 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /csharp/appendix-a/AlertingServerConsumer/alerting_server_consumer.cs: -------------------------------------------------------------------------------- 1 | /*############################################## 2 | # RabbitMQ in Action 3 | # Appendix A- Alerting Server Consumer (.NET) 4 | # 5 | # Requires: 6 | # * RabbitMQ.Client >= 2.7.0 7 | # * Newtonsoft.Json >= 4.0 8 | # 9 | # Author: Jason J. W. Williams 10 | # (C)2011 11 | ##############################################*/ 12 | 13 | using System; 14 | using System.Text; 15 | using System.Net.Mail; 16 | 17 | using Newtonsoft.Json; 18 | 19 | using RabbitMQ.Client; 20 | using RabbitMQ.Client.Events; 21 | 22 | namespace AlertingServer { 23 | class Consumer { 24 | 25 | private static void send_mail(string[] recipients, 26 | string subject, 27 | string message) { 28 | 29 | MailMessage msg = new MailMessage(); 30 | msg.From = new MailAddress("alerts@ourcompany.com"); 31 | 32 | foreach(string recip in recipients) 33 | msg.To.Add(recip); 34 | 35 | msg.Subject = subject; 36 | msg.Body = message; 37 | 38 | SmtpClient smtp_server = new SmtpClient("mail.ourcompany.com"); 39 | smtp_server.Port = 25; 40 | smtp_server.Send(msg); 41 | } 42 | 43 | private static void critical_notify(IBasicConsumer consumer, 44 | BasicDeliverEventArgs eargs) { 45 | 46 | string[] EMAIL_RECIPS = new string[] {"ops.team@ourcompany.com"}; 47 | 48 | IBasicProperties msg_props = eargs.BasicProperties; 49 | String msg_body = Encoding.ASCII.GetString(eargs.Body); 50 | 51 | //#/(ascdn.1) Decode our message from JSON 52 | msg_body = JsonConvert.DeserializeObject 53 | (msg_body); 54 | 55 | //#/(ascdn.2) Transmit e-mail to SMTP server 56 | send_mail(EMAIL_RECIPS, 57 | "CRITICAL ALERT", 58 | msg_body); 59 | 60 | Console.WriteLine("Sent alert via e-mail! Alert Text: " + 61 | msg_body + " Recipients: " + 62 | string.Join(",", EMAIL_RECIPS)); 63 | 64 | //#/(ascdn.3) Acknowledge the message 65 | consumer.Model.BasicAck(eargs.DeliveryTag, 66 | false); 67 | } 68 | 69 | private static void rate_limit_notify(IBasicConsumer consumer, 70 | BasicDeliverEventArgs eargs) { 71 | 72 | string[] EMAIL_RECIPS = new string[] {"api.team@ourcompany.com"}; 73 | 74 | IBasicProperties msg_props = eargs.BasicProperties; 75 | String msg_body = Encoding.ASCII.GetString(eargs.Body); 76 | 77 | //#/(ascdn.4) Decode our message from JSON 78 | msg_body = JsonConvert.DeserializeObject 79 | (msg_body); 80 | 81 | //#/(ascdn.5) Transmit e-mail to SMTP server 82 | send_mail(EMAIL_RECIPS, 83 | "RATE LIMIT ALERT!", 84 | msg_body); 85 | 86 | Console.WriteLine("Sent alert via e-mail! Alert Text: " + 87 | msg_body + " Recipients: " + 88 | string.Join(",", EMAIL_RECIPS)); 89 | 90 | //#/(ascdn.6) Acknowledge the message 91 | consumer.Model.BasicAck(eargs.DeliveryTag, 92 | false); 93 | } 94 | 95 | public static void Main(string[] args) { 96 | if(args.Length < 1) { 97 | Console.WriteLine("Must supply hostname."); 98 | Environment.Exit(-1); 99 | } 100 | 101 | var conn_factory = new ConnectionFactory(); 102 | 103 | conn_factory.HostName = args[0]; 104 | conn_factory.UserName = "alert_user"; 105 | conn_factory.Password = "alertme"; 106 | 107 | IConnection conn = conn_factory.CreateConnection(); 108 | IModel chan = conn.CreateModel(); 109 | 110 | chan.ExchangeDeclare("alerts", 111 | ExchangeType.Topic, 112 | true, 113 | false, 114 | null); 115 | 116 | chan.QueueDeclare("critical", 117 | false, 118 | false, 119 | false, 120 | null); 121 | 122 | chan.QueueBind("critical", "alerts", "critical.*"); 123 | 124 | chan.QueueDeclare("rate_limit", 125 | false, 126 | false, 127 | false, 128 | null); 129 | 130 | chan.QueueBind("rate_limit", "alerts", "*.rate_limit"); 131 | 132 | //#/(ascdn.7) Make our alert processors 133 | EventingBasicConsumer 134 | c_consumer = new EventingBasicConsumer {Model = chan}; 135 | c_consumer.Received += critical_notify; 136 | chan.BasicConsume("critical", 137 | false, 138 | c_consumer); 139 | 140 | 141 | EventingBasicConsumer 142 | r_consumer = new EventingBasicConsumer {Model = chan}; 143 | r_consumer.Received += rate_limit_notify; 144 | chan.BasicConsume("rate_limit", 145 | false, 146 | r_consumer); 147 | 148 | } 149 | } 150 | } -------------------------------------------------------------------------------- /csharp/appendix-a/AlertingServerProducer/AlertingServerProducer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {E0FE3136-6265-4D61-BDC7-FF3B68B31069} 9 | Exe 10 | Properties 11 | Project1 12 | AlertingServerProducer 13 | v4.0 14 | Client 15 | 512 16 | 17 | 18 | x86 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | x86 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | 40 | 41 | C:\Program Files\JSON.NET\Bin\Net35\Newtonsoft.Json.dll 42 | 43 | 44 | False 45 | C:\Program Files\RabbitMQ\DotNetClient\bin\RabbitMQ.Client.dll 46 | 47 | 48 | 49 | 56 | -------------------------------------------------------------------------------- /csharp/appendix-a/AlertingServerProducer/AlertingServerProducer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual C# Express 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AlertingServerProducer", "AlertingServerProducer.csproj", "{E0FE3136-6265-4D61-BDC7-FF3B68B31069}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|x86 = Debug|x86 9 | Release|x86 = Release|x86 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {E0FE3136-6265-4D61-BDC7-FF3B68B31069}.Debug|x86.ActiveCfg = Debug|x86 13 | {E0FE3136-6265-4D61-BDC7-FF3B68B31069}.Debug|x86.Build.0 = Debug|x86 14 | {E0FE3136-6265-4D61-BDC7-FF3B68B31069}.Release|x86.ActiveCfg = Release|x86 15 | {E0FE3136-6265-4D61-BDC7-FF3B68B31069}.Release|x86.Build.0 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /csharp/appendix-a/AlertingServerProducer/alerting_server_producer.cs: -------------------------------------------------------------------------------- 1 | /*############################################## 2 | # RabbitMQ in Action 3 | # Appendix A- Alerting Server Producer (.NET) 4 | # 5 | # Requires: 6 | # * RabbitMQ.Client >= 2.7.0 7 | # * Newtonsoft.Json >= 4.0 8 | # 9 | # Author: Jason J. W. Williams 10 | # (C)2011 11 | ##############################################*/ 12 | 13 | using System; 14 | using System.Text; 15 | 16 | using Newtonsoft.Json; 17 | 18 | using RabbitMQ.Client; 19 | using RabbitMQ.Client.Events; 20 | 21 | namespace AlertingServer { 22 | 23 | class Producer { 24 | 25 | public static void Main(string[] args) { 26 | if(args.Length < 3) { 27 | Console.WriteLine("Must supply hostname, routing key, " + 28 | "and alert message."); 29 | Environment.Exit(-1); 30 | } 31 | 32 | var conn_factory = new ConnectionFactory(); 33 | 34 | conn_factory.HostName = args[0]; 35 | conn_factory.UserName = "alert_user"; 36 | conn_factory.Password = "alertme"; 37 | 38 | //#/(aspdn.1) Establish connection to broker 39 | IConnection conn = conn_factory.CreateConnection(); 40 | IModel chan = conn.CreateModel(); //#/(hwcdn.2) Obtain channel 41 | 42 | //#/(aspdn.2) Publish alert message to broker 43 | string msg = JsonConvert.SerializeObject(args[2]); 44 | IBasicProperties msg_props = chan.CreateBasicProperties(); 45 | msg_props.ContentType = "application/json"; 46 | msg_props.DeliveryMode = 2; 47 | chan.BasicPublish("alerts", 48 | args[1], 49 | msg_props, 50 | Encoding.ASCII.GetBytes(msg)); 51 | 52 | Console.WriteLine("Sent message " + args[2] + 53 | " tagged with routing key " + args[1] + 54 | " to exchange 'alerts'."); 55 | 56 | Environment.Exit(0); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /csharp/appendix-a/HelloWorldConsumer/HelloWorldConsumer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {783053E0-7DF5-4CFA-B91F-7754D05756AE} 9 | Exe 10 | Properties 11 | HelloWorldConsumer 12 | HelloWorldConsumer 13 | v4.0 14 | Client 15 | 512 16 | 17 | 18 | x86 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | x86 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | 40 | 41 | False 42 | C:\Program Files\RabbitMQ\DotNetClient\bin\RabbitMQ.Client.dll 43 | 44 | 45 | 46 | 53 | -------------------------------------------------------------------------------- /csharp/appendix-a/HelloWorldConsumer/HelloWorldConsumer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual C# Express 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloWorldConsumer", "HelloWorldConsumer.csproj", "{783053E0-7DF5-4CFA-B91F-7754D05756AE}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|x86 = Debug|x86 9 | Release|x86 = Release|x86 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {783053E0-7DF5-4CFA-B91F-7754D05756AE}.Debug|x86.ActiveCfg = Debug|x86 13 | {783053E0-7DF5-4CFA-B91F-7754D05756AE}.Debug|x86.Build.0 = Debug|x86 14 | {783053E0-7DF5-4CFA-B91F-7754D05756AE}.Release|x86.ActiveCfg = Release|x86 15 | {783053E0-7DF5-4CFA-B91F-7754D05756AE}.Release|x86.Build.0 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /csharp/appendix-a/HelloWorldConsumer/hello_world_consumer.cs: -------------------------------------------------------------------------------- 1 | /*############################################## 2 | # RabbitMQ in Action 3 | # Appendix A- Hello World Consumer (.NET) 4 | # 5 | # Requires: 6 | # * RabbitMQ.Client >= 2.7.0 7 | # 8 | # Author: Jason J. W. Williams 9 | # (C)2011 10 | ##############################################*/ 11 | 12 | using System; 13 | using System.Text; 14 | 15 | using RabbitMQ.Client; 16 | using RabbitMQ.Client.Events; 17 | 18 | namespace HelloWorld { 19 | class Consumer { 20 | 21 | public static void Main(string[] args) { 22 | 23 | if(args.Length < 1) { 24 | Console.WriteLine("Must supply hostname."); 25 | Environment.Exit(-1); 26 | } 27 | 28 | var conn_factory = new ConnectionFactory(); 29 | 30 | conn_factory.HostName = args[0]; 31 | conn_factory.UserName = "guest"; 32 | conn_factory.Password = "guest"; 33 | 34 | //#/(hwcdn.1) Establish connection to broker 35 | IConnection conn = conn_factory.CreateConnection(); 36 | IModel chan = conn.CreateModel(); //#/(hwcdn.2) Obtain channel 37 | 38 | //#/(hwcdn.3) Declare the exchange 39 | chan.ExchangeDeclare("hello-exchange", 40 | ExchangeType.Direct, 41 | true, 42 | false, 43 | null); 44 | 45 | //#/(hwcdn.4) Declare the queue 46 | chan.QueueDeclare("hello-queue", 47 | false, 48 | false, 49 | false, 50 | null); 51 | 52 | //#/(hwcdn.5) Bind the queue and exchange together on the key "hola" 53 | chan.QueueBind("hello-queue", "hello-exchange", "hola"); 54 | 55 | //#/(hwcdn.6) Subscribe our consumer 56 | QueueingBasicConsumer consumer = new QueueingBasicConsumer(chan); 57 | String consumer_tag = chan.BasicConsume("hello-queue", false, consumer); 58 | 59 | //#/(hwcdn.7) Start consuming 60 | while(true) { 61 | //#/(hwcdn.8) Process incoming messages 62 | BasicDeliverEventArgs evt_args = (BasicDeliverEventArgs) consumer.Queue.Dequeue(); 63 | IBasicProperties msg_props = evt_args.BasicProperties; 64 | 65 | String msg_body = Encoding.ASCII.GetString(evt_args.Body); 66 | 67 | //#/(hwcdn.9) Message acknowledgement 68 | chan.BasicAck(evt_args.DeliveryTag, false); 69 | 70 | if(msg_body == "quit") { 71 | //#/(hwc.10) Stop consuming more messages and quit 72 | chan.BasicCancel(consumer_tag); 73 | break; 74 | } else 75 | Console.WriteLine("Message Body: " + msg_body); 76 | 77 | } 78 | 79 | Environment.Exit(0); 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /csharp/appendix-a/HelloWorldProducer/HelloWorldProducer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {B4328F8C-E6D6-49AE-ABB6-C70537BFB3F6} 9 | Exe 10 | Properties 11 | Project1 12 | HelloWorldProducer 13 | v4.0 14 | Client 15 | 512 16 | 17 | 18 | x86 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | x86 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | 40 | 41 | False 42 | C:\Program Files\RabbitMQ\DotNetClient\bin\RabbitMQ.Client.dll 43 | 44 | 45 | 46 | 53 | -------------------------------------------------------------------------------- /csharp/appendix-a/HelloWorldProducer/HelloWorldProducer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual C# Express 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloWorldProducer", "HelloWorldProducer.csproj", "{B4328F8C-E6D6-49AE-ABB6-C70537BFB3F6}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|x86 = Debug|x86 9 | Release|x86 = Release|x86 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {B4328F8C-E6D6-49AE-ABB6-C70537BFB3F6}.Debug|x86.ActiveCfg = Debug|x86 13 | {B4328F8C-E6D6-49AE-ABB6-C70537BFB3F6}.Debug|x86.Build.0 = Debug|x86 14 | {B4328F8C-E6D6-49AE-ABB6-C70537BFB3F6}.Release|x86.ActiveCfg = Release|x86 15 | {B4328F8C-E6D6-49AE-ABB6-C70537BFB3F6}.Release|x86.Build.0 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /csharp/appendix-a/HelloWorldProducer/hello_world_producer.cs: -------------------------------------------------------------------------------- 1 | /*############################################## 2 | # RabbitMQ in Action 3 | # Appendix A- Hello World Producer (.NET) 4 | # 5 | # Requires: 6 | # * RabbitMQ.Client >= 2.7.0 7 | # 8 | # Author: Jason J. W. Williams 9 | # (C)2011 10 | ##############################################*/ 11 | 12 | using System; 13 | using System.Text; 14 | 15 | using RabbitMQ.Client; 16 | using RabbitMQ.Client.Events; 17 | 18 | namespace HelloWorld { 19 | class Producer { 20 | 21 | public static void Main(string[] args) { 22 | 23 | //#/(hwpdn.1) Collect server and message 24 | if(args.Length < 2) { 25 | Console.WriteLine("Must supply hostname and " + 26 | "message text."); 27 | Environment.Exit(-1); 28 | } 29 | 30 | var conn_factory = new ConnectionFactory(); 31 | 32 | conn_factory.HostName = args[0]; 33 | conn_factory.UserName = "guest"; 34 | conn_factory.Password = "guest"; 35 | 36 | //#/(hwpdn.2) Establish connection to broker 37 | IConnection conn = conn_factory.CreateConnection(); 38 | IModel chan = conn.CreateModel(); //#/(hwpdn.2) Obtain channel 39 | 40 | //#/(hwpdn.3) Declare the exchange 41 | chan.ExchangeDeclare("hello-exchange", 42 | ExchangeType.Direct, 43 | true, 44 | false, 45 | null); 46 | 47 | //#/(hwpdn.4) Create a plaintext message 48 | string msg_body = args[1]; 49 | IBasicProperties msg_props = chan.CreateBasicProperties(); 50 | msg_props.ContentType = "text/plain"; 51 | 52 | //#/(hwpdn.5) Publish the message 53 | chan.BasicPublish("hello-exchange", 54 | "hola", 55 | msg_props, 56 | Encoding.ASCII.GetBytes(msg_body)); 57 | 58 | Environment.Exit(0); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /erlang/chapter-12/rabbitmq-recent-history-exchange/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | .DS_Store 3 | dist 4 | ebin 5 | erl_crash.dump -------------------------------------------------------------------------------- /erlang/chapter-12/rabbitmq-recent-history-exchange/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2011 Alvaro Videla 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /erlang/chapter-12/rabbitmq-recent-history-exchange/Makefile: -------------------------------------------------------------------------------- 1 | include ../umbrella.mk 2 | -------------------------------------------------------------------------------- /erlang/chapter-12/rabbitmq-recent-history-exchange/README.md: -------------------------------------------------------------------------------- 1 | # RabbitMQ Recent History Cache 2 | 3 | Keeps track of the last 20 messages that passed through the exchange. Every time a queue is bound to the exchange it delivers that last 20 messages to them. This is useful for implementing a very simple __Chat History__ where clients that join the conversation can get the latest messages. 4 | 5 | Exchange Type: `x-recent-history` 6 | 7 | ## Installation 8 | 9 | Install and setup the RabbitMQ Public Umbrella as explained here: [http://www.rabbitmq.com/plugin-development.html#getting-started](http://www.rabbitmq.com/plugin-development.html#getting-started). 10 | 11 | Then `cd` into the umbrella folder and type: 12 | 13 | $ git clone git://github.com/videlalvaro/rabbitmq-recent-history-exchange.git 14 | $ cd rabbitmq-recent-history-exchange 15 | $ make 16 | 17 | Finally copy all the `*.ez` files inside the `dist` folder to the `$RABBITMQ_HOME/plugins` folder. Don't copy the file `rabbit_common-x.y.z` since it's not needed inside the broker installation. 18 | 19 | ## License 20 | 21 | See LICENSE.md 22 | -------------------------------------------------------------------------------- /erlang/chapter-12/rabbitmq-recent-history-exchange/package.mk: -------------------------------------------------------------------------------- 1 | DEPS:=rabbitmq-server rabbitmq-erlang-client 2 | RETAIN_ORIGINAL_VERSION:=true 3 | 4 | -------------------------------------------------------------------------------- /erlang/chapter-12/rabbitmq-recent-history-exchange/src/rabbit_exchange_type_recent_history.erl: -------------------------------------------------------------------------------- 1 | -module(rabbit_exchange_type_recent_history). 2 | -include_lib("rabbit_common/include/rabbit.hrl"). 3 | -include_lib("rabbit_common/include/rabbit_exchange_type_spec.hrl"). 4 | 5 | -behaviour(rabbit_exchange_type). 6 | 7 | -export([description/0, serialise_events/0, route/2]). 8 | -export([validate/1, create/2, delete/3, add_binding/3, 9 | remove_bindings/3, assert_args_equivalence/2]). 10 | -export([setup_schema/0]). 11 | 12 | -rabbit_boot_step({rabbit_exchange_type_rh_registry, 13 | [{description, "recent history exchange type: registry"}, 14 | {mfa, {rabbit_registry, register, 15 | [exchange, <<"x-recent-history">>, 16 | ?MODULE]}}, 17 | {requires, rabbit_registry}, 18 | {enables, kernel_ready}]}). 19 | 20 | -rabbit_boot_step({rabbit_exchange_type_rh_mnesia, 21 | [{description, "recent history exchange type: mnesia"}, 22 | {mfa, {?MODULE, setup_schema, []}}, 23 | {requires, database}, 24 | {enables, external_infrastructure}]}). 25 | 26 | -define(KEEP_NB, 20). 27 | -define(RH_TABLE, rh_exchange_table). 28 | -record(cached, {key, content}). 29 | 30 | description() -> 31 | [{name, <<"recent-history">>}, 32 | {description, <<"List of Last-value caches exchange.">>}]. 33 | 34 | serialise_events() -> false. 35 | 36 | route(#exchange{name = XName}, 37 | #delivery{message = #basic_message{ 38 | content = Content 39 | }}) -> 40 | cache_msg(XName, Content), 41 | rabbit_router:match_routing_key(XName, ['_']). 42 | 43 | validate(_X) -> ok. 44 | create(_Tx, _X) -> ok. 45 | 46 | delete(_Tx, #exchange{ name = XName }, _Bs) -> 47 | rabbit_misc:execute_mnesia_transaction( 48 | fun() -> 49 | mnesia:delete(?RH_TABLE, XName, write) 50 | end), 51 | ok. 52 | 53 | add_binding(_Tx, #exchange{ name = XName }, 54 | #binding{ destination = QName }) -> 55 | case rabbit_amqqueue:lookup(QName) of 56 | {error, not_found} -> 57 | queue_not_found_error(QName); 58 | {ok, #amqqueue{ pid = QPid }} -> 59 | Cached = get_msgs_from_cache(XName), 60 | Msgs = msgs_from_content(XName, Cached), 61 | deliver_messages(QPid, Msgs) 62 | end, 63 | ok. 64 | 65 | remove_bindings(_Tx, _X, _Bs) -> ok. 66 | 67 | assert_args_equivalence(X, Args) -> 68 | rabbit_exchange:assert_args_equivalence(X, Args). 69 | 70 | setup_schema() -> 71 | case mnesia:create_table(?RH_TABLE, 72 | [{attributes, record_info(fields, cached)}, 73 | {record_name, cached}, 74 | {type, set}]) of 75 | {atomic, ok} -> ok; 76 | {aborted, {already_exists, ?RH_TABLE}} -> ok 77 | end. 78 | 79 | %%private 80 | cache_msg(XName, Content) -> 81 | rabbit_misc:execute_mnesia_transaction( 82 | fun () -> 83 | Cached = get_msgs_from_cache(XName), 84 | store_msg(XName, Cached, Content) 85 | end). 86 | 87 | get_msgs_from_cache(XName) -> 88 | rabbit_misc:execute_mnesia_transaction( 89 | fun () -> 90 | case mnesia:read(?RH_TABLE, XName) of 91 | [] -> 92 | []; 93 | [#cached{key = XName, content=Cached}] -> 94 | Cached 95 | end 96 | end). 97 | 98 | store_msg(Key, Cached, Content) -> 99 | mnesia:write(?RH_TABLE, 100 | #cached{key = Key, 101 | content = [Content|lists:sublist(Cached, ?KEEP_NB-1)]}, 102 | write). 103 | 104 | msgs_from_content(XName, Cached) -> 105 | lists:map( 106 | fun(Content) -> 107 | {Props, Payload} = rabbit_basic:from_content(Content), 108 | rabbit_basic:message(XName, <<"">>, Props, Payload) 109 | end, Cached). 110 | 111 | deliver_messages(Queue, Msgs) -> 112 | lists:map( 113 | fun (Msg) -> 114 | Delivery = rabbit_basic:delivery(false, false, Msg, undefined), 115 | rabbit_amqqueue:deliver(Queue, Delivery) 116 | end, lists:reverse(Msgs)). 117 | 118 | queue_not_found_error(QName) -> 119 | rabbit_misc:protocol_error( 120 | internal_error, 121 | "could not find queue '~s'", 122 | [QName]). -------------------------------------------------------------------------------- /erlang/chapter-12/rabbitmq-recent-history-exchange/src/rabbitmq_recent_history_exchange.app.src: -------------------------------------------------------------------------------- 1 | {application, rabbitmq_recent_history_exchange, 2 | [{description, "RabbitMQ Recent History Exchange"}, 3 | {vsn, "0.1.0"}, 4 | {modules, []}, 5 | {registered, []}, 6 | {applications, [kernel, stdlib, rabbit, mnesia]}]}. -------------------------------------------------------------------------------- /java/appendix-a/Client.java: -------------------------------------------------------------------------------- 1 | import com.rabbitmq.client.ConnectionFactory; 2 | import com.rabbitmq.client.Connection; 3 | import com.rabbitmq.client.Channel; 4 | import com.rabbitmq.client.QueueingConsumer; 5 | import com.rabbitmq.client.QueueingConsumer.Delivery; 6 | import com.rabbitmq.client.AMQP.BasicProperties; 7 | import org.json.JSONStringer; 8 | import org.json.JSONException; 9 | 10 | public class Client { 11 | 12 | private Connection connection; 13 | private Channel channel; 14 | private String replyQueueName; 15 | private QueueingConsumer consumer; 16 | 17 | public Client init() 18 | throws Exception { 19 | ConnectionFactory factory = new ConnectionFactory(); 20 | factory.setUsername("rpc_user"); 21 | factory.setPassword("rpcme"); 22 | connection = factory.newConnection(); 23 | channel = connection.createChannel(); 24 | return this; 25 | } 26 | 27 | public Client setupConsumer() 28 | throws Exception { 29 | replyQueueName = channel.queueDeclare().getQueue(); 30 | consumer = new QueueingConsumer(channel); 31 | channel.basicConsume(replyQueueName, false, consumer); 32 | return this; 33 | } 34 | 35 | public String call(String message) throws Exception { 36 | String response = null; 37 | 38 | channel.basicPublish( 39 | "rpc", 40 | "ping", 41 | getRequestProperties(), 42 | message.getBytes() 43 | ); 44 | 45 | System.out.println("Sent 'ping' RPC call. Waiting for reply..."); 46 | 47 | while (true) { 48 | Delivery delivery = consumer.nextDelivery(); 49 | response = new String(delivery.getBody(), "UTF-8"); 50 | break; 51 | } 52 | 53 | return response; 54 | } 55 | 56 | public void close() throws Exception { 57 | connection.close(); 58 | } 59 | 60 | private BasicProperties 61 | getRequestProperties() { 62 | return new BasicProperties 63 | .Builder() 64 | .replyTo(replyQueueName) 65 | .build(); 66 | } 67 | 68 | public static String createRequest() 69 | throws JSONException { 70 | float epoch = System.currentTimeMillis()/1000; 71 | JSONStringer msg = new JSONStringer(); 72 | return msg 73 | .object() 74 | .key("client_name") 75 | .value("RPC Client 1.0") 76 | .key("time") 77 | .value(Float.toString(epoch)) 78 | .endObject().toString(); 79 | } 80 | 81 | public static void main(String[] args) { 82 | Client client = null; 83 | String response = null; 84 | 85 | try { 86 | client = new Client(); 87 | client.init().setupConsumer(); 88 | response = client.call(Client.createRequest()); 89 | System.out.println("RPC Reply --- " + response); 90 | } 91 | catch (Exception e) { 92 | e.printStackTrace(); 93 | } 94 | finally { 95 | if (client!= null) { 96 | try { 97 | client.close(); 98 | } 99 | catch (Exception ignore) {} 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /java/appendix-a/Server.java: -------------------------------------------------------------------------------- 1 | import com.rabbitmq.client.ConnectionFactory; 2 | import com.rabbitmq.client.Connection; 3 | import com.rabbitmq.client.Channel; 4 | import com.rabbitmq.client.QueueingConsumer; 5 | import com.rabbitmq.client.QueueingConsumer.Delivery; 6 | import com.rabbitmq.client.AMQP.BasicProperties; 7 | import org.json.JSONObject; 8 | 9 | public class Server 10 | { 11 | private Connection connection; 12 | private Channel channel; 13 | private QueueingConsumer consumer; 14 | 15 | public Server Server(){ 16 | return this; 17 | } 18 | 19 | public Server init() 20 | throws Exception { 21 | ConnectionFactory factory = new ConnectionFactory(); 22 | factory.setUsername("rpc_user"); 23 | factory.setPassword("rpcme"); 24 | connection = factory.newConnection(); 25 | channel = connection.createChannel(); 26 | 27 | channel.exchangeDeclare("rpc", "direct"); 28 | channel.queueDeclare("ping", false, false, false, null); 29 | channel.queueBind("ping", "rpc", "ping"); 30 | 31 | consumer = new QueueingConsumer(channel); 32 | channel.basicConsume("ping", false, "ping", consumer); 33 | 34 | System.out.println( 35 | "Waiting for RPC calls..." 36 | ); 37 | 38 | return this; 39 | } 40 | 41 | public void closeConnection() { 42 | if (connection != null) { 43 | try { 44 | connection.close(); 45 | } 46 | catch (Exception ignore) {} 47 | } 48 | } 49 | 50 | public void serveRequests() { 51 | while (true) { 52 | try { 53 | 54 | Delivery delivery = consumer.nextDelivery(); 55 | BasicProperties props = delivery.getProperties(); 56 | 57 | channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false); 58 | System.out.println( 59 | "Received API call...replying..." 60 | ); 61 | 62 | channel.basicPublish( 63 | "", 64 | props.getReplyTo(), 65 | null, 66 | getResponse(delivery).getBytes("UTF-8") 67 | ); 68 | 69 | } catch (Exception e){ 70 | System.out.println(e.toString()); 71 | } 72 | } 73 | } 74 | 75 | private String getResponse(Delivery delivery) { 76 | String response = null; 77 | try { 78 | String message = new String(delivery.getBody(), "UTF-8"); 79 | JSONObject jsonobject = new JSONObject(message); 80 | response = "Pong!" + jsonobject.getString("time"); 81 | } 82 | catch (Exception e){ 83 | System.out.println(e.toString()); 84 | response = ""; 85 | } 86 | return response; 87 | } 88 | 89 | public static void main(String[] args) { 90 | Server server = null; 91 | try { 92 | server = new Server(); 93 | server.init().serveRequests(); 94 | } catch(Exception e) { 95 | e.printStackTrace(); 96 | } finally { 97 | if(server != null) { 98 | server.closeConnection(); 99 | } 100 | } 101 | } 102 | } -------------------------------------------------------------------------------- /php/chapter-1/hello-world-consumer.php: -------------------------------------------------------------------------------- 1 | channel(); 24 | 25 | $channel->exchange_declare($exchange, 26 | 'direct', 27 | false, 28 | true, 29 | false); 30 | 31 | $channel->queue_declare($queue); 32 | 33 | $channel->queue_bind($queue, $exchange); 34 | 35 | $consumer = function($msg){ 36 | $msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']); 37 | 38 | if($msg->body == 'quit'){ 39 | $msg->delivery_info['channel']->basic_cancel($msg->delivery_info['consumer_tag']); 40 | }else{ 41 | echo 'Hello ', $msg->body, "\n"; 42 | } 43 | }; 44 | 45 | $channel->basic_consume($queue, 46 | $consumer_tag, 47 | false, 48 | false, 49 | false, 50 | false, 51 | $consumer); 52 | 53 | while(count($channel->callbacks)) { 54 | $channel->wait(); 55 | } 56 | 57 | $channel->close(); 58 | $conn->close(); 59 | 60 | ?> -------------------------------------------------------------------------------- /php/chapter-1/hello-world-producer.php: -------------------------------------------------------------------------------- 1 | channel(); 21 | 22 | $channel->exchange_declare('hello-exchange', 23 | 'direct', 24 | false, 25 | true, 26 | false); 27 | 28 | $msg = new AMQPMessage($argv[1], 29 | array('content_type' => 'text/plain')); 30 | 31 | $channel->basic_publish($msg, 'hello-exchange'); 32 | 33 | $channel->close(); 34 | $conn->close(); 35 | ?> -------------------------------------------------------------------------------- /php/chapter-11/ssl_connection.php: -------------------------------------------------------------------------------- 1 | CERTS_PATH . '/rmqca/cacert.pem', 25 | 'local_cert' => CERTS_PATH . '/phpcert.pem', 26 | 'verify_peer' => true 27 | ); 28 | 29 | $conn = new AMQPSSLConnection(HOST, PORT, USER, PASS, VHOST, $ssl_options); 30 | 31 | function shutdown($conn){ 32 | $conn->close(); 33 | } 34 | 35 | register_shutdown_function('shutdown', $conn); 36 | 37 | while(1){} -------------------------------------------------------------------------------- /php/chapter-12/recent_history_consumer.php: -------------------------------------------------------------------------------- 1 | channel(); 22 | 23 | $ch->exchange_declare($exchange, 24 | 'x-recent-history', 25 | false, 26 | true, 27 | false); 28 | 29 | list($queue,,) = $ch->queue_declare(''); 30 | 31 | $ch->queue_bind($queue, $exchange); 32 | 33 | $consumer = function($msg){ 34 | echo $msg->body, "\t"; 35 | }; 36 | 37 | $ch->basic_consume( 38 | $queue, 39 | '', 40 | false, 41 | true, 42 | false, 43 | false, 44 | $consumer); 45 | 46 | echo "consuming from queue: ", $queue, "\n"; 47 | 48 | function shutdown($conn, $ch){ 49 | $ch->close(); 50 | $conn->close(); 51 | } 52 | 53 | register_shutdown_function('shutdown', $conn, $ch); 54 | 55 | while(count($ch->callbacks)) { 56 | $ch->wait(); 57 | } 58 | ?> -------------------------------------------------------------------------------- /php/chapter-12/recent_history_producer.php: -------------------------------------------------------------------------------- 1 | channel(); 21 | 22 | for($i=0; $i<100; $i++) { 23 | $msg = new AMQPMessage('msg_'.$i, 24 | array('content_type' => 'text/plain')); 25 | $channel->basic_publish($msg, 'rh-exchange'); 26 | } 27 | 28 | $channel->close(); 29 | $conn->close(); 30 | ?> -------------------------------------------------------------------------------- /php/chapter-3/rabbitmqctl-examples.php: -------------------------------------------------------------------------------- 1 | channel(); 13 | 14 | #/(rex.2) Declare the exchnage 15 | $channel->exchange_declare('logs-exchange', 16 | 'topic', false, true, false); 17 | 18 | #/(rex.3) Declare the queues 19 | $channel->queue_declare('msg-inbox-errors', 20 | false, true, false, false); 21 | 22 | $channel->queue_declare('msg-inbox-logs', 23 | false, true, false, false); 24 | 25 | $channel->queue_declare('all-logs', false, 26 | true, false, false); 27 | 28 | #/(rex.4) Bind the queues to the exchange 29 | $channel->queue_bind('msg-inbox-errors', 30 | 'logs-exchange', 'error.msg-inbox'); 31 | 32 | $channel->queue_bind('msg-inbox-logs', 33 | 'logs-exchange', '*.msg-inbox'); 34 | ?> -------------------------------------------------------------------------------- /php/chapter-4/listing-4.10.php: -------------------------------------------------------------------------------- 1 | channel(); 15 | 16 | $channel->exchange_declare('upload-pictures', 17 | 'fanout', false, true, false); 18 | 19 | $metadata = json_encode(array( 20 | 'image_id' => $argv[1], 21 | 'user_id' => $argv[2], 22 | 'image_path' => $argv[3] 23 | )); 24 | 25 | $msg = new AMQPMessage($metadata, array( 26 | 'content_type' => 'application/json', 27 | 'delivery_mode' => 2)); 28 | 29 | $channel->basic_publish($msg, 'upload-pictures'); 30 | 31 | $channel->close(); 32 | $conn->close(); 33 | ?> -------------------------------------------------------------------------------- /php/chapter-4/listing-4.11.php: -------------------------------------------------------------------------------- 1 | channel(); 16 | 17 | $channel->exchange_declare('upload-pictures', 18 | 'fanout', false, true, false); 19 | 20 | $channel->queue_declare('resize-picture', 21 | false, true, false, false); 22 | 23 | $channel->queue_bind('resize-picture', 'upload-pictures'); 24 | 25 | $consumer = function($msg){ 26 | 27 | if($msg->body == 'quit'){ 28 | $msg->delivery_info['channel']-> 29 | basic_cancel($msg->delivery_info['consumer_tag']); 30 | } 31 | 32 | $meta = json_decode($msg->body, true); 33 | 34 | resize_picture($meta['image_id'], $meta['image_path']); 35 | 36 | $msg->delivery_info['channel']-> 37 | basic_ack($msg->delivery_info['delivery_tag']); 38 | }; 39 | 40 | function resize_picture($image_id, $image_path){ 41 | echo sprintf("Resizing picture: %s %s\n", 42 | $image_id, $image_path); 43 | } 44 | 45 | $channel->basic_consume($queue, 46 | $consumer_tag, 47 | false, 48 | false, 49 | false, 50 | false, 51 | $consumer); 52 | 53 | while(count($channel->callbacks)) { 54 | $channel->wait(); 55 | } 56 | 57 | $channel->close(); 58 | $conn->close(); 59 | ?> -------------------------------------------------------------------------------- /php/chapter-4/listing-4.7.php: -------------------------------------------------------------------------------- 1 | channel(); 15 | 16 | $channel->exchange_declare('upload-pictures', 17 | 'fanout', false, true, false); 18 | 19 | $metadata = json_encode(array( 20 | 'image_id' => $image_id, 21 | 'user_id' => $user_id, 22 | 'image_path' => $image_path 23 | )); 24 | 25 | $msg = new AMQPMessage($metadata, 26 | array('content_type' => 'application/json', 27 | 'delivery_mode' => 2)); 28 | 29 | $channel->basic_publish($msg, 'upload-pictures'); 30 | 31 | $channel->close(); 32 | $conn->close(); 33 | 34 | ?> -------------------------------------------------------------------------------- /php/chapter-4/listing-4.8.php: -------------------------------------------------------------------------------- 1 | channel(); 15 | 16 | $channel->exchange_declare('upload-pictures', 17 | 'fanout', false, true, false); 18 | 19 | $channel->queue_declare('add-points', 20 | false, true, false, false); 21 | 22 | $channel->queue_bind('add-points', 'upload-pictures'); 23 | 24 | $consumer = function($msg){}; 25 | 26 | $channel->basic_consume($queue, 27 | $consumer_tag, 28 | false, 29 | false, 30 | false, 31 | false, 32 | $consumer); 33 | 34 | $channel->close(); 35 | $conn->close(); 36 | 37 | ?> 38 | -------------------------------------------------------------------------------- /php/chapter-4/listing-4.9.php: -------------------------------------------------------------------------------- 1 | channel(); 15 | 16 | function add_points_to_user($user_id){ 17 | echo sprintf("Adding points to user: %s\n", $user_id); 18 | } 19 | 20 | $consumer = function($msg){ 21 | 22 | if($msg->body == 'quit'){ 23 | $msg->delivery_info['channel']-> 24 | basic_cancel($msg->delivery_info['consumer_tag']); 25 | } 26 | 27 | $meta = json_decode($msg->body, true); 28 | 29 | add_points_to_user($meta['user_id']); 30 | 31 | $msg->delivery_info['channel']-> 32 | basic_ack($msg->delivery_info['delivery_tag']); 33 | }; 34 | 35 | $channel->close(); 36 | $conn->close(); 37 | 38 | ?> -------------------------------------------------------------------------------- /php/config/config.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pika-0.9.6.tar.bz2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rabbitinaction/sourcecode/27cb99b6778702993972b4ffd512c95fb95ebeb6/pika-0.9.6.tar.bz2 -------------------------------------------------------------------------------- /python/chapter-10/amqp_ping_check.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 10 - RabbitMQ ping (AMQP) check. 4 | ############################################### 5 | # 6 | # 7 | # Author: Jason J. W. Williams 8 | # (C)2011 9 | ############################################### 10 | import sys, pika 11 | 12 | #(nc.0) Nagios status codes 13 | EXIT_OK = 0 14 | EXIT_WARNING = 1 15 | EXIT_CRITICAL = 2 16 | EXIT_UNKNOWN = 3 17 | 18 | #/(nc.1) Parse command line arguments 19 | server, port = sys.argv[1].split(":") 20 | vhost = sys.argv[2] 21 | username = sys.argv[3] 22 | password = sys.argv[4] 23 | 24 | #/(nc.2) Establish connection to broker 25 | creds_broker = pika.PlainCredentials(username, password) 26 | conn_params = pika.ConnectionParameters(server, 27 | virtual_host = vhost, 28 | credentials = creds_broker) 29 | try: 30 | conn_broker = pika.BlockingConnection(conn_params) 31 | channel = conn_broker.channel() 32 | except Exception: 33 | #/(nc.3) Connection failed, return CRITICAL status 34 | print "CRITICAL: Could not connect to %s:%s!" % (server, port) 35 | exit(EXIT_CRITICAL) 36 | 37 | #(nc.4) Connection OK, return OK status 38 | print "OK: Connect to %s:%s successful." % (server, port) 39 | exit(EXIT_OK) -------------------------------------------------------------------------------- /python/chapter-10/amqp_queue_count_check.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 10 - Queue count (AMQP) check. 4 | ############################################### 5 | # 6 | # 7 | # Author: Jason J. W. Williams 8 | # (C)2011 9 | ############################################### 10 | import sys, pika, socket 11 | 12 | #(aqcc.0) Nagios status codes 13 | EXIT_OK = 0 14 | EXIT_WARNING = 1 15 | EXIT_CRITICAL = 2 16 | EXIT_UNKNOWN = 3 17 | 18 | #/(aqcc.1) Parse command line arguments 19 | server, port = sys.argv[1].split(":") 20 | vhost = sys.argv[2] 21 | username = sys.argv[3] 22 | password = sys.argv[4] 23 | queue_name = sys.argv[5] 24 | max_critical = int(sys.argv[6]) 25 | max_warn = int(sys.argv[7]) 26 | 27 | #/(aqcc.2) Establish connection to broker 28 | creds_broker = pika.PlainCredentials(username, password) 29 | conn_params = pika.ConnectionParameters(server, 30 | virtual_host = vhost, 31 | credentials = creds_broker) 32 | try: 33 | conn_broker = pika.BlockingConnection(conn_params) 34 | channel = conn_broker.channel() 35 | except socket.timeout: 36 | #/(aqcc.3) Connection failed, return unknown status 37 | print "Unknown: Could not connect to %s:%s!" % (server, port) 38 | exit(EXIT_UNKNOWN) 39 | 40 | try: 41 | response = channel.queue_declare(queue=queue_name, 42 | passive=True) 43 | except pika.exceptions.AMQPChannelError: 44 | print "CRITICAL: Queue %s does not exist." % queue_name 45 | exit(EXIT_CRITICAL) 46 | 47 | #(aqcc.4) Message count is above critical limit 48 | if response.method.message_count >= max_critical: 49 | print "CRITICAL: Queue %s message count: %d" % \ 50 | (queue_name, response.method.message_count) 51 | exit(EXIT_CRITICAL) 52 | 53 | #(aqcc.5) Message count is above warning limit 54 | if response.method.message_count >= max_warn: 55 | print "WARN: Queue %s message count: %d" % \ 56 | (queue_name, response.method.message_count) 57 | exit(EXIT_WARNING) 58 | 59 | #(aqcc.6) Connection OK, return OK status 60 | print "OK: Queue %s message count: %d" % \ 61 | (queue_name, response.method.message_count) 62 | exit(EXIT_OK) -------------------------------------------------------------------------------- /python/chapter-10/api_ping_check.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 10 - RabbitMQ ping (HTTP API) check. 4 | ############################################### 5 | # 6 | # 7 | # Author: Jason J. W. Williams 8 | # (C)2011 9 | ############################################### 10 | 11 | import sys, json, httplib, urllib, base64, socket 12 | 13 | #(apic.0) Nagios status codes 14 | EXIT_OK = 0 15 | EXIT_WARNING = 1 16 | EXIT_CRITICAL = 2 17 | EXIT_UNKNOWN = 3 18 | 19 | #/(apic.1) Parse arguments 20 | server, port = sys.argv[1].split(":") 21 | vhost = sys.argv[2] 22 | username = sys.argv[3] 23 | password = sys.argv[4] 24 | 25 | #/(apic.2) Connect to server 26 | conn = httplib.HTTPConnection(server, port) 27 | 28 | #/(apic.3) Build API path 29 | path = "/api/aliveness-test/%s" % urllib.quote(vhost, safe="") 30 | method = "GET" 31 | 32 | #/(apic.4) Issue API request 33 | credentials = base64.b64encode("%s:%s" % (username, password)) 34 | 35 | try: 36 | conn.request(method, path, "", 37 | {"Content-Type" : "application/json", 38 | "Authorization" : "Basic " + credentials}) 39 | 40 | #/(apic.5) Could not connect to API server, return critical status 41 | except socket.error: 42 | print "CRITICAL: Could not connect to %s:%s" % (server, port) 43 | exit(EXIT_CRITICAL) 44 | 45 | response = conn.getresponse() 46 | 47 | #/(apic.6) RabbitMQ not responding/alive, return critical status 48 | if response.status > 299: 49 | print "CRITICAL: Broker not alive: %s" % response.read() 50 | exit(EXIT_CRITICAL) 51 | 52 | #/(apic.7) RabbitMQ alive, return OK status 53 | print "OK: Broker alive: %s" % response.read() 54 | exit(EXIT_OK) 55 | -------------------------------------------------------------------------------- /python/chapter-10/api_queue_count_check.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 10 - Queue count (HTTP API) check. 4 | ############################################### 5 | # 6 | # 7 | # Author: Jason J. W. Williams 8 | # (C)2011 9 | ############################################### 10 | 11 | import sys, json, httplib, urllib, base64, socket 12 | 13 | #(aqcc.0) Nagios status codes 14 | EXIT_OK = 0 15 | EXIT_WARNING = 1 16 | EXIT_CRITICAL = 2 17 | EXIT_UNKNOWN = 3 18 | 19 | #/(aqcc.1) Parse arguments 20 | server, port = sys.argv[1].split(":") 21 | vhost = sys.argv[2] 22 | username = sys.argv[3] 23 | password = sys.argv[4] 24 | queue_name = sys.argv[5] 25 | max_unack_critical = int(sys.argv[6]) 26 | max_unack_warn = int(sys.argv[7]) 27 | max_ready_critical = int(sys.argv[8]) 28 | max_ready_warn = int(sys.argv[9]) 29 | 30 | 31 | #/(aqcc.2) Connect to server 32 | conn = httplib.HTTPConnection(server, port) 33 | 34 | #/(aqcc.3) Build API path 35 | path = "/api/queues/%s/%s" % (urllib.quote(vhost, safe=""), 36 | queue_name) 37 | method = "GET" 38 | 39 | #/(aqcc.4) Issue API request 40 | credentials = base64.b64encode("%s:%s" % (username, password)) 41 | 42 | try: 43 | conn.request(method, path, "", 44 | {"Content-Type" : "application/json", 45 | "Authorization" : "Basic " + credentials}) 46 | 47 | #/(aqcc.5) Could not connect to API server, return unknown status 48 | except socket.error: 49 | print "UNKNOWN: Could not connect to %s:%s" % (server, port) 50 | exit(EXIT_UNKNOWN) 51 | 52 | response = conn.getresponse() 53 | 54 | #/(aqcc.6) RabbitMQ not responding/alive, return critical status 55 | if response.status > 299: 56 | print "UNKNOWN: Unexpected API error: %s" % response.read() 57 | exit(EXIT_UNKNOWN) 58 | 59 | #/(aqcc.7) Extract message count levels from response 60 | resp_payload = json.loads(response.read()) 61 | msg_cnt_unack = resp_payload["messages_unacknowledged"] 62 | msg_cnt_ready = resp_payload["messages_ready"] 63 | msg_cnt_total = resp_payload["messages"] 64 | 65 | #/(aqcc.8) Consumed but unacknowledged message count above thresholds 66 | if msg_cnt_unack >= max_unack_critical: 67 | print "CRITICAL: %s - %d unack'd messages." % (queue_name, 68 | msg_cnt_unack) 69 | exit(EXIT_CRITICAL) 70 | elif msg_cnt_unack >= max_unack_warn: 71 | print "WARN: %s - %d unack'd messages." % (queue_name, 72 | msg_cnt_unack) 73 | exit(EXIT_WARNING) 74 | 75 | #/(aqcc.9) Ready to be consumed message count above thresholds 76 | if msg_cnt_ready >= max_ready_critical: 77 | print "CRITICAL: %s - %d unconsumed messages." % (queue_name, 78 | msg_cnt_ready) 79 | exit(EXIT_CRITICAL) 80 | elif msg_cnt_ready >= max_ready_warn: 81 | print "WARN: %s - %d unconsumed messages." % (queue_name, 82 | msg_cnt_ready) 83 | exit(EXIT_WARNING) 84 | 85 | #/(aqcc.10) Message counts below thresholds, return OK status 86 | print "OK: %s - %d in-flight messages. %dB used memory." % \ 87 | (queue_name, msg_cnt_total, resp_payload["memory"]) 88 | exit(EXIT_OK) -------------------------------------------------------------------------------- /python/chapter-10/cluster_health_check.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 10 - Cluster health check. 4 | ############################################### 5 | # 6 | # 7 | # Author: Jason J. W. Williams 8 | # (C)2011 9 | ############################################### 10 | 11 | import sys, json, httplib, base64, socket 12 | 13 | #(chc.0) Nagios status codes 14 | EXIT_OK = 0 15 | EXIT_WARNING = 1 16 | EXIT_CRITICAL = 2 17 | EXIT_UNKNOWN = 3 18 | 19 | #/(chc.1) Parse arguments 20 | server, port = sys.argv[1].split(":") 21 | username = sys.argv[2] 22 | password = sys.argv[3] 23 | node_list = sys.argv[4].split(",") 24 | mem_critical = int(sys.argv[5]) 25 | mem_warning = int(sys.argv[6]) 26 | 27 | #/(chc.2) Connect to server 28 | conn = httplib.HTTPConnection(server, port) 29 | 30 | #/(chc.3) Build API path 31 | path = "/api/nodes" 32 | method = "GET" 33 | 34 | #/(chc.4) Issue API request 35 | credentials = base64.b64encode("%s:%s" % (username, password)) 36 | try: 37 | conn.request(method, path, "", 38 | {"Content-Type" : "application/json", 39 | "Authorization" : "Basic " + credentials}) 40 | #/(chc.5) Could not connect to API server, return unknown status 41 | except socket.error: 42 | print "UNKNOWN: Could not connect to %s:%s" % (server, port) 43 | exit(EXIT_UNKNOWN) 44 | 45 | response = conn.getresponse() 46 | 47 | #/(chc.6) Unexpected API error, return unknown status 48 | if response.status > 299: 49 | print "UNKNOWN: Unexpected API error: %s" % response.read() 50 | exit(EXIT_UNKNOWN) 51 | 52 | #/(chc.7) Parse API response 53 | response = json.loads(response.read()) 54 | 55 | #/(chc.8) Cluster is missing nodes, return warning status 56 | for node in response: 57 | if node["name"] in node_list and node["running"] != False: 58 | node_list.remove(node["name"]) 59 | 60 | if len(node_list): 61 | print "WARNING: Cluster missing nodes: %s" % str(node_list) 62 | exit(EXIT_WARNING) 63 | 64 | #/(chc.9) Node used memory is over limit 65 | for node in response: 66 | if node["mem_used"] > mem_critical: 67 | print "CRITICAL: Node %s memory usage is %d." % \ 68 | (node["name"], node["mem_used"]) 69 | exit(EXIT_CRITICAL) 70 | elif node["mem_used"] > mem_warning: 71 | print "WARNING: Node %s memory usage is %d." % \ 72 | (node["name"], node["mem_used"]) 73 | exit(EXIT_WARNING) 74 | 75 | #/(chc.10) All nodes present and used memory below limit 76 | print "OK: %d nodes. All memory usage below %d." % (len(response), 77 | mem_warning) 78 | exit(EXIT_OK) -------------------------------------------------------------------------------- /python/chapter-10/nagios_check.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 10 - Basic Nagios check. 4 | ############################################### 5 | # 6 | # 7 | # Author: Jason J. W. Williams 8 | # (C)2011 9 | ############################################### 10 | import sys, json, httplib, base64 11 | 12 | #/(nc.1) Return requested Nagios status code 13 | status = sys.argv[1] 14 | 15 | if status.lower() == "warning": 16 | print "Status is WARN" 17 | exit(1) 18 | elif status.lower() == "critical": 19 | print "Status is CRITICAL" 20 | exit(2) 21 | elif status.lower() == "unknown": 22 | print "Status is UNKNOWN" 23 | exit(3) 24 | else: 25 | print "Status is OK" 26 | exit(0) 27 | -------------------------------------------------------------------------------- /python/chapter-10/queue_config_check.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 10 - Queue config watchdog check. 4 | ############################################### 5 | # 6 | # 7 | # Author: Jason J. W. Williams 8 | # (C)2011 9 | ############################################### 10 | 11 | import sys, json, httplib, urllib, base64, socket 12 | 13 | #(qcwc.0) Nagios status codes 14 | EXIT_OK = 0 15 | EXIT_WARNING = 1 16 | EXIT_CRITICAL = 2 17 | EXIT_UNKNOWN = 3 18 | 19 | #/(qcwc.1) Parse arguments 20 | server, port = sys.argv[1].split(":") 21 | vhost = sys.argv[2] 22 | username = sys.argv[3] 23 | password = sys.argv[4] 24 | queue_name = sys.argv[5] 25 | auto_delete = json.loads(sys.argv[6].lower()) 26 | durable = json.loads(sys.argv[7].lower()) 27 | 28 | #/(qcwc.2) Connect to server 29 | conn = httplib.HTTPConnection(server, port) 30 | 31 | #/(qcwc.3) Build API path 32 | path = "/api/queues/%s/%s" % (urllib.quote(vhost, safe=""), 33 | urllib.quote(queue_name)) 34 | method = "GET" 35 | 36 | #/(qcwc.4) Issue API request 37 | credentials = base64.b64encode("%s:%s" % (username, password)) 38 | try: 39 | conn.request(method, path, "", 40 | {"Content-Type" : "application/json", 41 | "Authorization" : "Basic " + credentials}) 42 | #/(qcwc.5) Could not connect to API server, return unknown status 43 | except socket.error: 44 | print "UNKNOWN: Could not connect to %s:%s" % (server, port) 45 | exit(EXIT_UNKNOWN) 46 | 47 | response = conn.getresponse() 48 | 49 | #/(qcwc.6) Queue does not exist, return critical status 50 | if response.status == 404: 51 | print "CRITICAL: Queue %s does not exist." % queue_name 52 | exit(EXIT_CRITICAL) 53 | #/(qcwc.7) Unexpected API error, return unknown status 54 | elif response.status > 299: 55 | print "UNKNOWN: Unexpected API error: %s" % response.read() 56 | exit(EXIT_UNKNOWN) 57 | 58 | #/(qcwc.8) Parse API response 59 | response = json.loads(response.read()) 60 | 61 | #/(qcwc.9) Queue auto_delete flag incorrect, return warning status 62 | if response["auto_delete"] != auto_delete: 63 | print "WARN: Queue '%s' - auto_delete flag is NOT %s." % \ 64 | (queue_name, auto_delete) 65 | exit(EXIT_WARNING) 66 | 67 | #/(qcwc.10) Queue durable flag incorrect, return warning status 68 | if response["durable"] != durable: 69 | print "WARN: Queue '%s' - durable flag is NOT %s." % \ 70 | (queue_name, durable) 71 | exit(EXIT_WARNING) 72 | 73 | 74 | #/(qcwc.11) Queue exists and it's flags are correct, return OK status 75 | print "OK: Queue %s configured correctly." % queue_name 76 | exit(EXIT_OK) -------------------------------------------------------------------------------- /python/chapter-2/hello_world_consumer.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 1 - Hello World Consumer 4 | # 5 | # Requires: pika >= 0.9.5 6 | # 7 | # Author: Jason J. W. Williams 8 | # (C)2011 9 | ############################################### 10 | 11 | import pika 12 | 13 | credentials = pika.PlainCredentials("guest", "guest") 14 | conn_params = pika.ConnectionParameters("localhost", 15 | credentials = credentials) 16 | conn_broker = pika.BlockingConnection(conn_params) #/(hwc.1) Establish connection to broker 17 | 18 | 19 | channel = conn_broker.channel() #/(hwc.2) Obtain channel 20 | 21 | channel.exchange_declare(exchange="hello-exchange", #/(hwc.3) Declare the exchange 22 | type="direct", 23 | passive=False, 24 | durable=True, 25 | auto_delete=False) 26 | 27 | channel.queue_declare(queue="hello-queue") #/(hwc.4) Declare the queue 28 | 29 | channel.queue_bind(queue="hello-queue", #/(hwc.5) Bind the queue and exchange together on the key "hola" 30 | exchange="hello-exchange", 31 | routing_key="hola") 32 | 33 | 34 | def msg_consumer(channel, method, header, body): #/(hwc.6) Make function to process incoming messages 35 | 36 | channel.basic_ack(delivery_tag=method.delivery_tag) #/(hwc.7) Message acknowledgement 37 | 38 | if body == "quit": 39 | channel.basic_cancel(consumer_tag="hello-consumer") #/(hwc.8) Stop consuming more messages and quit 40 | channel.stop_consuming() 41 | else: 42 | print body 43 | 44 | return 45 | 46 | 47 | 48 | channel.basic_consume( msg_consumer, #/(hwc.9) Subscribe our consumer 49 | queue="hello-queue", 50 | consumer_tag="hello-consumer") 51 | 52 | channel.start_consuming() #/(hwc.10) Start consuming -------------------------------------------------------------------------------- /python/chapter-2/hello_world_producer.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 1 - Hello World Producer 4 | # 5 | # Requires: pika >= 0.9.5 6 | # 7 | # Author: Jason J. W. Williams 8 | # (C)2011 9 | ############################################### 10 | 11 | import pika, sys 12 | 13 | credentials = pika.PlainCredentials("guest", "guest") 14 | conn_params = pika.ConnectionParameters("localhost", 15 | credentials = credentials) 16 | conn_broker = pika.BlockingConnection(conn_params) #/(hwp.1) Establish connection to broker 17 | 18 | 19 | channel = conn_broker.channel() #/(hwp.2) Obtain channel 20 | 21 | channel.exchange_declare(exchange="hello-exchange", #/(hwp.3) Declare the exchange 22 | type="direct", 23 | passive=False, 24 | durable=True, 25 | auto_delete=False) 26 | 27 | msg = sys.argv[1] 28 | msg_props = pika.BasicProperties() 29 | msg_props.content_type = "text/plain" #/(hwp.4) Create a plaintext message 30 | 31 | channel.basic_publish(body=msg, 32 | exchange="hello-exchange", 33 | properties=msg_props, 34 | routing_key="hola") #/(hwp.5) Publish the message -------------------------------------------------------------------------------- /python/chapter-2/hello_world_producer_pubconfirm.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 1 - Hello World Producer 4 | # w/ Publisher Confirms 5 | # 6 | # Requires: pika >= 0.9.6 7 | # 8 | # Author: Jason J. W. Williams 9 | # (C)2011 10 | ############################################### 11 | 12 | import pika, sys 13 | from pika import spec 14 | 15 | credentials = pika.PlainCredentials("guest", "guest") 16 | conn_params = pika.ConnectionParameters("localhost", 17 | credentials = credentials) 18 | conn_broker = pika.BlockingConnection(conn_params) 19 | 20 | channel = conn_broker.channel() 21 | 22 | def confirm_handler(frame): #/(hwppc.1) Publisher confirm handler 23 | if type(frame.method) == spec.Confirm.SelectOk: 24 | print "Channel in 'confirm' mode." 25 | elif type(frame.method) == spec.Basic.Nack: 26 | if frame.method.delivery_tag in msg_ids: 27 | print "Message lost!" 28 | elif type(frame.method) == spec.Basic.Ack: 29 | if frame.method.delivery_tag in msg_ids: 30 | print "Confirm received!" 31 | msg_ids.remove(frame.method.delivery_tag) 32 | 33 | #/(hwppc.2) Put channel in "confirm" mode 34 | channel.confirm_delivery(callback=confirm_handler) 35 | 36 | msg = sys.argv[1] 37 | msg_props = pika.BasicProperties() 38 | msg_props.content_type = "text/plain" 39 | 40 | msg_ids = [] #/(hwppc.3) Reset message ID tracker 41 | 42 | channel.basic_publish(body=msg, 43 | exchange="hello-exchange", 44 | properties=msg_props, 45 | routing_key="hola") #/(hwppc.4) Publish the message 46 | 47 | msg_ids.append(len(msg_ids) + 1) #/(hwppc.5) Add ID to tracking list 48 | 49 | channel.close() 50 | 51 | -------------------------------------------------------------------------------- /python/chapter-2/hello_world_producer_tx.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 1 - Hello World Producer 4 | # w/ Transactions 5 | # 6 | # Requires: pika >= 0.9.5 7 | # 8 | # Author: Jason J. W. Williams 9 | # (C)2011 10 | ############################################### 11 | 12 | import pika, sys 13 | 14 | credentials = pika.PlainCredentials("guest", "guest") 15 | conn_params = pika.ConnectionParameters("localhost", 16 | credentials = credentials) 17 | conn_broker = pika.BlockingConnection(conn_params) #/(hwp.1) Establish connection to broker 18 | 19 | 20 | channel = conn_broker.channel() #/(hwp.2) Obtain channel 21 | 22 | channel.exchange_declare(exchange="hello-exchange", #/(hwp.3) Declare the exchange 23 | type="direct", 24 | passive=False, 25 | durable=True, 26 | auto_delete=False) 27 | 28 | msg = sys.argv[1] 29 | msg_props = pika.BasicProperties() 30 | msg_props.content_type = "text/plain" #/(hwp.4) Create a plaintext message 31 | 32 | channel.tx_select() 33 | channel.basic_publish(body=msg, 34 | exchange="hello-exchange", 35 | properties=msg_props, 36 | routing_key="hola") #/(hwp.5) Publish the message 37 | channel.tx_commit() -------------------------------------------------------------------------------- /python/chapter-4/alert_consumer.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 4.2.2 - Alerting Server Consumer 4 | # 5 | # Requires: pika >= 0.9.5 6 | # 7 | # Author: Jason J. W. Williams 8 | # (C)2011 9 | ############################################### 10 | import json, smtplib 11 | import pika 12 | 13 | 14 | def send_mail(recipients, subject, message): 15 | """E-mail generator for received alerts.""" 16 | headers = ("From: %s\r\nTo: \r\nDate: \r\n" + \ 17 | "Subject: %s\r\n\r\n") % ("alerts@ourcompany.com", 18 | subject) 19 | 20 | smtp_server = smtplib.SMTP() 21 | smtp_server.connect("mail.ourcompany.com", 25) 22 | smtp_server.sendmail("alerts@ourcompany.com", 23 | recipients, 24 | headers + str(message)) 25 | smtp_server.close() 26 | 27 | #/(asc.5) Notify Processors 28 | def critical_notify(channel, method, header, body): 29 | """Sends CRITICAL alerts to administrators via e-mail.""" 30 | 31 | EMAIL_RECIPS = ["ops.team@ourcompany.com",] 32 | 33 | #/(asc.6) Decode our message from JSON 34 | message = json.loads(body) 35 | 36 | #/(asc.7) Transmit e-mail to SMTP server 37 | send_mail(EMAIL_RECIPS, "CRITICAL ALERT", message) 38 | print ("Sent alert via e-mail! Alert Text: %s " + \ 39 | "Recipients: %s") % (str(message), str(EMAIL_RECIPS)) 40 | 41 | #/(asc.8) Acknowledge the message 42 | channel.basic_ack(delivery_tag=method.delivery_tag) 43 | 44 | def rate_limit_notify(channel, method, header, body): 45 | """Sends the message to the administrators via e-mail.""" 46 | 47 | EMAIL_RECIPS = ["api.team@ourcompany.com",] 48 | 49 | #/(asc.9) Decode our message from JSON 50 | message = json.loads(body) 51 | 52 | #/(asc.10) Transmit e-mail to SMTP server 53 | send_mail(EMAIL_RECIPS, "RATE LIMIT ALERT!", message) 54 | 55 | print ("Sent alert via e-mail! Alert Text: %s " + \ 56 | "Recipients: %s") % (str(message), str(EMAIL_RECIPS)) 57 | 58 | #/(asc.11) Acknowledge the message 59 | channel.basic_ack(delivery_tag=method.delivery_tag) 60 | 61 | 62 | if __name__ == "__main__": 63 | #/(asc.0) Broker settings 64 | AMQP_SERVER = "localhost" 65 | AMQP_USER = "alert_user" 66 | AMQP_PASS = "alertme" 67 | AMQP_VHOST = "/" 68 | AMQP_EXCHANGE = "alerts" 69 | 70 | #/(asc.1) Establish connection to broker 71 | creds_broker = pika.PlainCredentials(AMQP_USER, AMQP_PASS) 72 | conn_params = pika.ConnectionParameters(AMQP_SERVER, 73 | virtual_host = AMQP_VHOST, 74 | credentials = creds_broker) 75 | conn_broker = pika.BlockingConnection(conn_params) 76 | 77 | channel = conn_broker.channel() 78 | 79 | #/(asc.2) Declare the Exchange 80 | channel.exchange_declare( exchange=AMQP_EXCHANGE, 81 | type="topic", 82 | auto_delete=False) 83 | 84 | #/(asc.3) Build the queues and bindings for our topics 85 | channel.queue_declare(queue="critical", auto_delete=False) 86 | channel.queue_bind(queue="critical", 87 | exchange="alerts", 88 | routing_key="critical.*") 89 | 90 | channel.queue_declare(queue="rate_limit", auto_delete=False) 91 | channel.queue_bind(queue="rate_limit", 92 | exchange="alerts", 93 | routing_key="*.rate_limit") 94 | 95 | #/(asc.4) Make our alert processors 96 | 97 | channel.basic_consume( critical_notify, 98 | queue="critical", 99 | no_ack=False, 100 | consumer_tag="critical") 101 | 102 | channel.basic_consume( rate_limit_notify, 103 | queue="rate_limit", 104 | no_ack=False, 105 | consumer_tag="rate_limit") 106 | 107 | print "Ready for alerts!" 108 | channel.start_consuming() 109 | -------------------------------------------------------------------------------- /python/chapter-4/alert_producer.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 4.2.2 - Alerting Server Producer 4 | # 5 | # Requires: pika >= 0.9.5 6 | # 7 | # Author: Jason J. W. Williams 8 | # (C)2011 9 | ############################################### 10 | import json, pika 11 | from optparse import OptionParser 12 | 13 | #/(asp.0) Read in command line arguments 14 | opt_parser = OptionParser() 15 | opt_parser.add_option("-r", 16 | "--routing-key", 17 | dest="routing_key", 18 | help="Routing key for message (e.g. myalert.im)") 19 | opt_parser.add_option("-m", 20 | "--message", 21 | dest="message", 22 | help="Message text for alert.") 23 | 24 | args = opt_parser.parse_args()[0] 25 | 26 | #/(asp.1) Establish connection to broker 27 | creds_broker = pika.PlainCredentials("alert_user", "alertme") 28 | conn_params = pika.ConnectionParameters("localhost", 29 | virtual_host = "/", 30 | credentials = creds_broker) 31 | conn_broker = pika.BlockingConnection(conn_params) 32 | 33 | channel = conn_broker.channel() 34 | 35 | #/(asp.2) Publish alert message to broker 36 | msg = json.dumps(args.message) 37 | msg_props = pika.BasicProperties() 38 | msg_props.content_type = "application/json" 39 | msg_props.durable = False 40 | 41 | channel.basic_publish(body=msg, 42 | exchange="alerts", 43 | properties=msg_props, 44 | routing_key=args.routing_key) 45 | 46 | print ("Sent message %s tagged with routing key '%s' to " + \ 47 | "exchange '/'.") % (json.dumps(args.message), 48 | args.routing_key) -------------------------------------------------------------------------------- /python/chapter-4/rpc_client.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 4.3.3 - RPC Client 4 | # 5 | # Requires: pika >= 0.9.5 6 | # 7 | # Author: Jason J. W. Williams 8 | # (C)2011 9 | ############################################### 10 | import time, json, pika 11 | 12 | #/(rpcc.0) Establish connection to broker 13 | creds_broker = pika.PlainCredentials("rpc_user", "rpcme") 14 | conn_params = pika.ConnectionParameters("localhost", 15 | virtual_host = "/", 16 | credentials = creds_broker) 17 | conn_broker = pika.BlockingConnection(conn_params) 18 | channel = conn_broker.channel() 19 | 20 | #/(rpcc.1) Issue RPC call & wait for reply 21 | msg = json.dumps({"client_name": "RPC Client 1.0", 22 | "time" : time.time()}) 23 | 24 | result = channel.queue_declare(exclusive=True, auto_delete=True) 25 | msg_props = pika.BasicProperties() 26 | msg_props.reply_to=result.method.queue 27 | 28 | channel.basic_publish(body=msg, 29 | exchange="rpc", 30 | properties=msg_props, 31 | routing_key="ping") 32 | 33 | print "Sent 'ping' RPC call. Waiting for reply..." 34 | 35 | def reply_callback(channel, method, header, body): 36 | """Receives RPC server replies.""" 37 | print "RPC Reply --- " + body 38 | channel.stop_consuming() 39 | 40 | 41 | 42 | channel.basic_consume(reply_callback, 43 | queue=result.method.queue, 44 | consumer_tag=result.method.queue) 45 | 46 | channel.start_consuming() -------------------------------------------------------------------------------- /python/chapter-4/rpc_server.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 4.3.3 - RPC Server 4 | # 5 | # Requires: pika >= 0.9.5 6 | # 7 | # Author: Jason J. W. Williams 8 | # (C)2011 9 | ############################################### 10 | 11 | import pika, json 12 | 13 | #/(apiserver.0) Establish connection to broker 14 | creds_broker = pika.PlainCredentials("rpc_user", "rpcme") 15 | conn_params = pika.ConnectionParameters("localhost", 16 | virtual_host = "/", 17 | credentials = creds_broker) 18 | conn_broker = pika.BlockingConnection(conn_params) 19 | channel = conn_broker.channel() 20 | 21 | #/(apiserver.1) Declare Exchange & "ping" Call Queue 22 | channel.exchange_declare(exchange="rpc", 23 | type="direct", 24 | auto_delete=False) 25 | channel.queue_declare(queue="ping", auto_delete=False) 26 | channel.queue_bind(queue="ping", 27 | exchange="rpc", 28 | routing_key="ping") 29 | 30 | #/(apiserver.2) Wait for RPC calls and reply 31 | def api_ping(channel, method, header, body): 32 | """'ping' API call.""" 33 | channel.basic_ack(delivery_tag=method.delivery_tag) 34 | msg_dict = json.loads(body) 35 | print "Received API call...replying..." 36 | channel.basic_publish(body="Pong!" + str(msg_dict["time"]), 37 | exchange="", 38 | routing_key=header.reply_to) 39 | 40 | channel.basic_consume(api_ping, 41 | queue="ping", 42 | consumer_tag="ping") 43 | 44 | print "Waiting for RPC calls..." 45 | channel.start_consuming() -------------------------------------------------------------------------------- /python/chapter-5/hello_world_mirrored_queue_consumer.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 5 - Hello World Consumer 4 | # (Mirrored Queues) 5 | # 6 | # Requires: pika >= 0.9.5 7 | # 8 | # Author: Jason J. W. Williams 9 | # (C)2011 10 | ############################################### 11 | 12 | import pika 13 | 14 | credentials = pika.PlainCredentials("guest", "guest") 15 | conn_params = pika.ConnectionParameters("localhost", 16 | credentials = credentials) 17 | conn_broker = pika.BlockingConnection(conn_params) #/(hwcmq.1) Establish connection to broker 18 | 19 | 20 | channel = conn_broker.channel() #/(hwcmq.2) Obtain channel 21 | 22 | channel.exchange_declare(exchange="hello-exchange", #/(hwcmq.3) Declare the exchange 23 | type="direct", 24 | passive=False, 25 | durable=True, 26 | auto_delete=False) 27 | 28 | queue_args = {"x-ha-policy" : "all" } #/(hwcmq.4) Set queue mirroring policy 29 | 30 | channel.queue_declare(queue="hello-queue", arguments=queue_args) #/(hwcmq.5) Declare the queue 31 | 32 | channel.queue_bind(queue="hello-queue", #/(hwcmq.6) Bind the queue and exchange together on the key "hola" 33 | exchange="hello-exchange", 34 | routing_key="hola") 35 | 36 | 37 | def msg_consumer(channel, method, header, body): #/(hwcmq.7) Make function to process incoming messages 38 | 39 | channel.basic_ack(delivery_tag=method.delivery_tag) #/(hwcmq.8) Message acknowledgement 40 | 41 | if body == "quit": 42 | channel.basic_cancel(consumer_tag="hello-consumer") #/(hwcmq.9) Stop consuming more messages and quit 43 | channel.stop_consuming() 44 | else: 45 | print body 46 | 47 | return 48 | 49 | 50 | 51 | channel.basic_consume( msg_consumer, #/(hwc.9) Subscribe our consumer 52 | queue="hello-queue", 53 | consumer_tag="hello-consumer") 54 | 55 | channel.start_consuming() #/(hwc.10) Start consuming -------------------------------------------------------------------------------- /python/chapter-5/hello_world_mirrored_queue_consumer_selective_nodes.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 5 - Hello World Consumer 4 | # (Mirrored Queues) 5 | # 6 | # Requires: pika >= 0.9.5 7 | # 8 | # Author: Jason J. W. Williams 9 | # (C)2011 10 | ############################################### 11 | 12 | import pika 13 | 14 | credentials = pika.PlainCredentials("guest", "guest") 15 | conn_params = pika.ConnectionParameters("localhost", 16 | credentials = credentials) 17 | conn_broker = pika.BlockingConnection(conn_params) #/(hwcmq.1) Establish connection to broker 18 | 19 | 20 | channel = conn_broker.channel() #/(hwcmq.2) Obtain channel 21 | 22 | channel.exchange_declare(exchange="hello-exchange", #/(hwcmq.3) Declare the exchange 23 | type="direct", 24 | passive=False, 25 | durable=True, 26 | auto_delete=False) 27 | 28 | queue_args = {"x-ha-policy" : "nodes", 29 | "x-ha-policy-params" : ["rabbit@Phantome", 30 | "rabbit2@Phantome"]} #/(hwcmq.4) Set queue mirroring policy 31 | 32 | channel.queue_declare(queue="hello-queue", arguments=queue_args) #/(hwcmq.5) Declare the queue 33 | 34 | channel.queue_bind(queue="hello-queue", #/(hwcmq.6) Bind the queue and exchange together on the key "hola" 35 | exchange="hello-exchange", 36 | routing_key="hola") 37 | 38 | 39 | def msg_consumer(channel, method, header, body): #/(hwcmq.7) Make function to process incoming messages 40 | 41 | channel.basic_ack(delivery_tag=method.delivery_tag) #/(hwcmq.8) Message acknowledgement 42 | 43 | if body == "quit": 44 | channel.basic_cancel(consumer_tag="hello-consumer") #/(hwcmq.9) Stop consuming more messages and quit 45 | channel.stop_consuming() 46 | else: 47 | print body 48 | 49 | return 50 | 51 | 52 | 53 | channel.basic_consume( msg_consumer, #/(hwc.9) Subscribe our consumer 54 | queue="hello-queue", 55 | consumer_tag="hello-consumer") 56 | 57 | channel.start_consuming() #/(hwc.10) Start consuming -------------------------------------------------------------------------------- /python/chapter-6/cluster_test_consumer.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 5 - Cluster Test Consumer 4 | # 5 | # Requires: pika >= 0.9.5 6 | # 7 | # Author: Jason J. W. Williams 8 | # (C)2011 9 | ############################################### 10 | import sys, json, pika, time, traceback 11 | 12 | 13 | def msg_rcvd(channel, method, header, body): 14 | message = json.loads(body) 15 | 16 | #/(ctc.1) Print & acknowledge our message 17 | print "Received: %(content)s/%(time)d" % message 18 | channel.basic_ack(delivery_tag=method.delivery_tag) 19 | 20 | 21 | if __name__ == "__main__": 22 | #/(ctc.2) Broker settings 23 | AMQP_SERVER = sys.argv[1] 24 | AMQP_PORT = int(sys.argv[2]) 25 | 26 | #/(ctc.3) Establish broker connection settings 27 | creds_broker = pika.PlainCredentials("guest", "guest") 28 | conn_params = pika.ConnectionParameters( AMQP_SERVER, 29 | port=AMQP_PORT, 30 | virtual_host="/", 31 | credentials=creds_broker) 32 | 33 | 34 | #/(ctc.4) On fault, reconnect to RabbitMQ 35 | while True: 36 | try: 37 | #/(ctc.5) Establish connection to RabbitMQ 38 | conn_broker = pika.BlockingConnection(conn_params) 39 | 40 | #/(ctc.6) Custom connection behavior 41 | channel = conn_broker.channel() 42 | #/(ctc.7) Declare the exchange, queues & bindings 43 | channel.exchange_declare( exchange="cluster_test", 44 | type="direct", 45 | auto_delete=False) 46 | channel.queue_declare( queue="cluster_test", 47 | auto_delete=False) 48 | channel.queue_bind( queue="cluster_test", 49 | exchange="cluster_test", 50 | routing_key="cluster_test") 51 | 52 | #/(ctc.8) Start consuming messages 53 | print "Ready for testing!" 54 | channel.basic_consume( msg_rcvd, 55 | queue="cluster_test", 56 | no_ack=False, 57 | consumer_tag="cluster_test") 58 | channel.start_consuming() 59 | #/(ctc.9) Trap connection errors and print them 60 | except Exception, e: 61 | traceback.print_exc() 62 | 63 | 64 | -------------------------------------------------------------------------------- /python/chapter-6/cluster_test_producer.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 5 - Cluster Test Producer 4 | # 5 | # Requires: pika >= 0.9.5 6 | # 7 | # Author: Jason J. W. Williams 8 | # (C)2011 9 | ############################################### 10 | import sys, time, json, pika 11 | 12 | AMQP_HOST = sys.argv[1] 13 | AMQP_PORT = int(sys.argv[2]) 14 | 15 | #/(ctp.1) Establish connection to broker 16 | creds_broker = pika.PlainCredentials("guest", "guest") 17 | conn_params = pika.ConnectionParameters(AMQP_HOST, 18 | port=AMQP_PORT, 19 | virtual_host = "/", 20 | credentials = creds_broker) 21 | 22 | conn_broker = pika.BlockingConnection(conn_params) 23 | 24 | channel = conn_broker.channel() 25 | 26 | #/(ctp.2) Connect to RabbitMQ and send message 27 | 28 | msg = json.dumps({"content": "Cluster Test!", 29 | "time" : time.time()}) 30 | msg_props = pika.BasicProperties(content_type="application/json") 31 | 32 | channel.basic_publish(body=msg, mandatory=True, 33 | exchange="", 34 | properties=msg_props, 35 | routing_key="cluster_test") 36 | 37 | print "Sent cluster test message." 38 | 39 | -------------------------------------------------------------------------------- /python/chapter-7/shovel_consumer.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 5 - Shovel Test Consumer 4 | # 5 | # Requires: pika >= 0.9.5 6 | # 7 | # Author: Jason J. W. Williams 8 | # (C)2011 9 | ############################################### 10 | import sys, json, pika, time, traceback 11 | 12 | 13 | def msg_rcvd(channel, method, header, body): 14 | message = json.loads(body) 15 | 16 | #/(ctc.1) Print & acknowledge our order 17 | print "Received order %(ordernum)d for %(type)s." % message 18 | channel.basic_ack(delivery_tag=method.delivery_tag) 19 | 20 | 21 | if __name__ == "__main__": 22 | #/(ctc.2) Broker settings 23 | AMQP_SERVER = sys.argv[1] 24 | AMQP_PORT = int(sys.argv[2]) 25 | 26 | #/(ctc.3) Establish broker connection settings 27 | creds_broker = pika.PlainCredentials("guest", "guest") 28 | conn_params = pika.ConnectionParameters( AMQP_SERVER, 29 | port=AMQP_PORT, 30 | virtual_host="/", 31 | credentials=creds_broker) 32 | 33 | #/(ctc.5) Establish connection to RabbitMQ 34 | conn_broker = pika.BlockingConnection(conn_params) 35 | channel = conn_broker.channel() 36 | 37 | #/(ctc.8) Start processing orders 38 | print "Ready for orders!" 39 | channel.basic_consume( msg_rcvd, 40 | queue="warehouse_carpinteria", 41 | no_ack=False, 42 | consumer_tag="order_processor") 43 | channel.start_consuming() 44 | -------------------------------------------------------------------------------- /python/chapter-7/shovel_producer.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 5 - Shovel Test Producer 4 | # 5 | # Requires: pika >= 0.9.5 6 | # 7 | # Author: Jason J. W. Williams 8 | # (C)2011 9 | ############################################### 10 | import sys, json, pika, random 11 | 12 | AMQP_HOST = sys.argv[1] 13 | AMQP_PORT = int(sys.argv[2]) 14 | AVOCADO_TYPE = sys.argv[3] 15 | 16 | #/(ctp.1) Establish connection to broker 17 | creds_broker = pika.PlainCredentials("guest", "guest") 18 | conn_params = pika.ConnectionParameters(AMQP_HOST, 19 | port=AMQP_PORT, 20 | virtual_host = "/", 21 | credentials = creds_broker) 22 | 23 | conn_broker = pika.BlockingConnection(conn_params) 24 | 25 | channel = conn_broker.channel() 26 | 27 | #/(ctp.2) Connect to RabbitMQ and send message 28 | 29 | msg = json.dumps({"ordernum": random.randrange(0, 100, 1), 30 | "type" : AVOCADO_TYPE}) 31 | msg_props = pika.BasicProperties(content_type="application/json") 32 | 33 | channel.basic_publish(body=msg, mandatory=True, 34 | exchange="incoming_orders", 35 | properties=msg_props, 36 | routing_key="warehouse") 37 | 38 | print "Sent avocado order message." 39 | 40 | -------------------------------------------------------------------------------- /python/chapter-9/node_lister.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 9 - RMQ Node Lister 4 | ############################################### 5 | # 6 | # 7 | # Author: Jason J. W. Williams 8 | # (C)2011 9 | ############################################### 10 | import sys, json, httplib, base64 11 | 12 | #/(nl.1) Assign arguments 13 | if len(sys.argv) < 4: 14 | print "USAGE: node_lister.py server_name:port auth_user auth_pass" 15 | sys.exit(1) 16 | 17 | server, port = sys.argv[1].split(":") 18 | username = sys.argv[2] 19 | password = sys.argv[3] 20 | 21 | #/(nl.2) Connect to server 22 | conn = httplib.HTTPConnection(server, port) 23 | 24 | #/(nl.3) Build API path 25 | path = "/api/nodes" 26 | method = "GET" 27 | 28 | #/(nl.4) Issue API request 29 | credentials = base64.b64encode("%s:%s" % (username, password)) 30 | conn.request(method, path, "", 31 | {"Content-Type" : "application/json", 32 | "Authorization" : "Basic " + credentials}) 33 | response = conn.getresponse() 34 | if response.status > 299: 35 | print "Error executing API call (%d): %s" % (response.status, 36 | response.read()) 37 | sys.exit(2) 38 | 39 | #/(nl.6) Parse and display node list 40 | resp_payload = json.loads(response.read()) 41 | for node in resp_payload: 42 | print "Node '%(name)s'" % node 43 | print "================" 44 | print "\t Memory Used: %(mem_used)d" % node 45 | print "\t Memory Limit: %(mem_limit)d" % node 46 | print "\t Uptime (secs): %(uptime)d" % node 47 | print "\t CPU Count: %(processors)d" % node 48 | print "\t Node Type: %(type)s" % node 49 | print "\t Erlang Version: %(erlang_version)s" % node 50 | print "\n" 51 | print "\tInstalled Apps/Plugins" 52 | print "\t----------------------" 53 | for app in node["applications"]: 54 | print "\t\t%(name)s" % app 55 | print "\t\t\tVersion: %(version)s" % app 56 | print "\t\t\tDescription: %(description)s\n" % app 57 | 58 | sys.exit(0) -------------------------------------------------------------------------------- /python/chapter-9/queue_stats.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 9 - RMQ Queue Statistics 4 | ############################################### 5 | # 6 | # Author: Jason J. W. Williams 7 | # (C)2011 8 | ############################################### 9 | import sys, json, httplib, urllib, base64 10 | 11 | #/(qs.0) Validate argument count 12 | if len(sys.argv) < 6: 13 | print "USAGE: queue_stats.py server_name:port auth_user auth_pass VHOST QUEUE_NAME" 14 | sys.exit(1) 15 | 16 | #/(qs.1) Assign arguments to memorable variables 17 | server, port = sys.argv[1].split(":") 18 | username = sys.argv[2] 19 | password = sys.argv[3] 20 | vhost = sys.argv[4] 21 | queue_name = sys.argv[5] 22 | 23 | #/(qs.2) Build API path 24 | vhost = urllib.quote(vhost, safe='') 25 | queue_name = urllib.quote(queue_name, safe='') 26 | path = "/api/queues/%s/%s" % (vhost, queue_name) 27 | #/(qs.3) Set the request method 28 | method = "GET" 29 | 30 | #/(qs.4) Connect to the API server 31 | conn = httplib.HTTPConnection(server, port) 32 | #/(qs.5) Base64 the username/password 33 | credentials = base64.b64encode("%s:%s" % (username, password)) 34 | #/(qs.6) Set the content-type and credentials 35 | headers = {"Content-Type" : "application/json", 36 | "Authorization" : "Basic " + credentials} 37 | #/(qs.7) Send the request 38 | conn.request(method, path, "", headers) 39 | #/(qs.8) Receive the response. 40 | response = conn.getresponse() 41 | if response.status > 299: 42 | print "Error executing API call (%d): %s" % (response.status, 43 | response.read()) 44 | sys.exit(2) 45 | 46 | #/(qs.9) Decode response 47 | resp_payload = json.loads(response.read()) 48 | 49 | #/(qs.10) Display queue statistics 50 | print "'%s' Queue Stats" % urllib.unquote(queue_name) 51 | print "-----------------" 52 | print "\tMemory Used (bytes): " + str(resp_payload["memory"]) 53 | print "\tConsumer Count: " + str(resp_payload["consumers"]) 54 | print "\tMessages:" 55 | print "\t\tUnack'd: " + str(resp_payload["messages_unacknowledged"]) 56 | print "\t\tReady: " + str(resp_payload["messages_ready"]) 57 | print "\t\tTotal: " + str(resp_payload["messages"]) 58 | 59 | sys.exit(0) -------------------------------------------------------------------------------- /python/chapter-9/user_manager.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 9 - RMQ User Manager 4 | ############################################### 5 | # 6 | # USAGE: 7 | # # user_vhost_manager.py "host" "auth_user" "auth_pass" create 'user' 'password' 'true/false' 8 | # "host" "auth_user" "auth_pass" delete 'user' 9 | # "host" "auth_user" "auth_pass" list 10 | # "host" "auth_user" "auth_pass" show 'user' 11 | # 12 | # Author: Jason J. W. Williams 13 | # (C)2011 14 | ############################################### 15 | import sys, json, httplib, base64 16 | 17 | #/(um.1) Assign arguments 18 | if len(sys.argv) < 5: 19 | print "USAGE: user_manager.py server_name:port auth_user auth_pass", 20 | print "ACTION [PARAMS...]" 21 | sys.exit(1) 22 | 23 | server, port = sys.argv[1].split(":") 24 | username = sys.argv[2] 25 | password = sys.argv[3] 26 | action = sys.argv[4] 27 | 28 | if len(sys.argv) > 5: 29 | res_params = sys.argv[5:] 30 | else: 31 | res_params = [] 32 | 33 | #/(um.2) Build API path 34 | base_path = "/api/users" 35 | 36 | if action == "list": 37 | path = base_path 38 | method = "GET" 39 | if action == "create": 40 | path = base_path + "/" + res_params[0] 41 | method = "PUT" 42 | if action == "delete": 43 | path = base_path + "/" + res_params[0] 44 | method = "DELETE" 45 | if action == "show": 46 | path = base_path + "/" + res_params[0] 47 | method = "GET" 48 | 49 | 50 | #/(um.3) Build JSON arguments 51 | json_args = "" 52 | if action == "create": 53 | json_args = {"password" : res_params[1], 54 | "administrator" : json.loads(res_params[2])} 55 | json_args = json.dumps(json_args) 56 | 57 | #/(um.4) Issue API request 58 | conn = httplib.HTTPConnection(server, port) 59 | credentials = base64.b64encode("%s:%s" % (username, password)) 60 | conn.request(method, path, json_args, 61 | {"Content-Type" : "application/json", 62 | "Authorization" : "Basic " + credentials}) 63 | response = conn.getresponse() 64 | if response.status > 299: 65 | print "Error executing API call (%d): %s" % (response.status, 66 | response.read()) 67 | sys.exit(2) 68 | 69 | #/(um.5) Parse and display response 70 | resp_payload = response.read() 71 | if action in ["list", "show"]: 72 | resp_payload = json.loads(resp_payload) 73 | 74 | #/(um.6) Process 'list' results 75 | if action == "list": 76 | print "Count: %d" % len(resp_payload) 77 | for user in resp_payload: 78 | print "User: %(name)s" % user 79 | print "\tPassword: %(password_hash)s" % user 80 | print "\tAdministrator: %(administrator)s\n" % user 81 | 82 | #/(um.7) Process 'show' results 83 | if action == "show": 84 | print "User: %(name)s" % resp_payload 85 | print "\tPassword: %(password_hash)s" % resp_payload 86 | print "\tAdministrator: %(administrator)s\n" % resp_payload 87 | #/(um.8) Create and delete requests have no result. 88 | else: 89 | print "Completed request!" 90 | 91 | sys.exit(0) -------------------------------------------------------------------------------- /python/chapter-9/user_vhost_manager.py: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # RabbitMQ in Action 3 | # Chapter 9 - RMQ User & Vhost Manager 4 | # 5 | # USAGE: 6 | # # user_vhost_manager.py "host" "auth_user" "auth_pass" create vhost 'vhostname' 7 | # "host" "auth_user" "auth_pass" delete vhost 'vhostname' 8 | # "host" "auth_user" "auth_pass" list vhost 9 | # "host" "auth_user" "auth_pass" show vhost 'vhostname' 10 | # "host" "auth_user" "auth_pass" create user 'user' 'password' 'true/false' 11 | # "host" "auth_user" "auth_pass" delete user 'user' 12 | # "host" "auth_user" "auth_pass" list user 13 | # "host" "auth_user" "auth_pass" show user 'user' 14 | # "host" "auth_user" "auth_pass" show permission 'user' 'vhost' 15 | # "host" "auth_user" "auth_pass" create permission 'user' 'vhost' 'read' 'write' 'configure' 16 | # 17 | # Author: Jason J. W. Williams 18 | # (C)2011 19 | ############################################### 20 | import sys, json, httplib, base64 21 | 22 | base_path = "/api/%ss" 23 | 24 | #/(uvm.1) Assign arguments 25 | if len(sys.argv) < 6: 26 | print "USAGE: user_vhost_manager.py server_name:port auth_user auth_pass", 27 | print "ACTION RESOURCE [PARAMS...]" 28 | sys.exit(1) 29 | 30 | server, port = sys.argv[1].split(":") 31 | username = sys.argv[2] 32 | password = sys.argv[3] 33 | action = sys.argv[4] 34 | res_type = sys.argv[5] 35 | 36 | if len(sys.argv) > 6: 37 | res_params = sys.argv[6:] 38 | else: 39 | res_params = [] 40 | 41 | #/(uvm.2) Connect to server 42 | conn = httplib.HTTPConnection(server, port) 43 | 44 | #/(uvm.3) Build API request 45 | if action == "list": 46 | path = base_path % res_type 47 | method = "GET" 48 | else: 49 | if res_type == "permission": 50 | path = (base_path % res_type) + ("/%s/%s" % (res_params[0], 51 | res_params[1])) 52 | else: 53 | path = (base_path % res_type) + "/" + res_params[0] 54 | 55 | if action == "create": 56 | method = "PUT" 57 | elif action == "delete": 58 | method = "DELETE" 59 | elif action == "show": 60 | method = "GET" 61 | 62 | 63 | #/(uvm.4) Build JSON arguments 64 | json_args = "" 65 | if action == "create" and res_type == "user": 66 | json_args = {"password" : res_params[1], 67 | "administrator" : json.loads(res_params[2])} 68 | json_args = json.dumps(json_args) 69 | 70 | if action == "create" and res_type == "permission": 71 | json_args = {"read" : res_params[2], 72 | "write" : res_params[3], 73 | "configure" : res_params[4]} 74 | json_args = json.dumps(json_args) 75 | 76 | #/(uvm.5) Issue API call 77 | credentials = base64.b64encode("%s:%s" % (username, password)) 78 | conn.request(method, path, json_args, 79 | {"Content-Type" : "application/json", 80 | "Authorization" : "Basic " + credentials}) 81 | response = conn.getresponse() 82 | if response.status > 299: 83 | print "Error executing API call (%d): %s" % (response.status, 84 | response.read()) 85 | sys.exit(2) 86 | 87 | #/(uvm.6) Parse and display response 88 | resp_payload = response.read() 89 | if action in ["list", "show"]: 90 | resp_payload = json.loads(resp_payload) 91 | 92 | #/(uvm.7) Process 'list' results 93 | if action == "list": 94 | print "Count: %d" % len(resp_payload) 95 | if res_type == "vhost": 96 | for vhost in resp_payload: 97 | print "Vhost: %(name)s" % vhost 98 | elif res_type == "user": 99 | for user in resp_payload: 100 | print "User: %(name)s" % user 101 | print "\tPassword: %(password_hash)s" % user 102 | print "\tAdministrator: %(administrator)s\n" % user 103 | 104 | #/(uvm.8) Process 'show' results 105 | elif action == "show": 106 | if res_type == "vhost": 107 | print "Vhost: %(name)s" % resp_payload 108 | elif res_type == "user": 109 | print "User: %(name)s" % resp_payload 110 | print "\tPassword: %(password_hash)s" % resp_payload 111 | print "\tAdministrator: %(administrator)s\n" % resp_payload 112 | elif res_type == "permission": 113 | print "Permissions for '%(user)s' in '%(vhost)s'..." % resp_payload 114 | print "\tRead: %(read)s" % resp_payload 115 | print "\tWrite: %(write)s" % resp_payload 116 | print "\tConfig: %(configure)s" % resp_payload 117 | else: 118 | print "Completed request!" 119 | 120 | sys.exit(0) -------------------------------------------------------------------------------- /ruby/.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *# 3 | *.class 4 | *.rbc 5 | Gemfile.lock -------------------------------------------------------------------------------- /ruby/Gemfile: -------------------------------------------------------------------------------- 1 | source :rubygems 2 | 3 | gem "amqp", "~> 0.8.3" -------------------------------------------------------------------------------- /ruby/chapter-2/hello_world_consumer.rb: -------------------------------------------------------------------------------- 1 | if defined?(Bundler); Bundler.setup; else; require "rubygems"; end 2 | 3 | require "amqp" 4 | 5 | EventMachine.run do 6 | 7 | AMQP.connect(:host => "localhost", :username => "guest", :password => "guest") do |connection| 8 | puts "Connected. Waiting for messages... Hit Control + C to stop me." 9 | 10 | channel = AMQP::Channel.new(connection) 11 | exchange = channel.direct("hello-exchange", :durable => true, :auto_delete => false) 12 | channel.queue("hello-queue", :durable => true, :auto_delete => false).bind(exchange, :routing_key => "hola").subscribe do |header, body| 13 | 14 | if body == "quit" 15 | connection.close { EventMachine.stop } 16 | else 17 | puts body 18 | end 19 | end 20 | 21 | # stop on Control + c 22 | stop = Proc.new { connection.close { EventMachine.stop } } 23 | Signal.trap("INT", &stop) 24 | end 25 | end -------------------------------------------------------------------------------- /ruby/chapter-2/hello_world_producer.rb: -------------------------------------------------------------------------------- 1 | if defined?(Bundler); Bundler.setup; else; require "rubygems"; end 2 | 3 | require "amqp" 4 | 5 | EventMachine.run do 6 | AMQP.connect(:host => "localhost", :username => "guest", :password => "guest") do |connection| 7 | puts "Connected. Hit Control + C to stop me." 8 | 9 | channel = AMQP::Channel.new(connection) 10 | channel.direct("hello-exchange", :durable => true, :auto_delete => false). 11 | publish(ARGV[0], :routing_key => "hola") 12 | 13 | # stop on Control + c or after 1 second 14 | stop = Proc.new { connection.close { EventMachine.stop } } 15 | Signal.trap("INT", &stop) 16 | EventMachine.add_timer(1, &stop) 17 | end 18 | end --------------------------------------------------------------------------------