├── .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
--------------------------------------------------------------------------------