1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
|
<chapter>
<title>Qpid High Level Client API</title>
<para>The Apache Qpid High Level Client API is a reliable,
asynchronous messaging API that is similar to Java JMS, but designed
to support programming in other commonly used programming languages,
and to support cross-platform messaging using the AMQP protocol. It
is currently implemented for C++ and Python. The addressing
mechanisms it defines can also be used in Java JMS.</para>
<para>Unlike earlier Qpid APIs, the High Level Client API does not
expose the details of the underlying messaging protocol or the
software components defined by the protocol. Instead, it defines a
declarative syntax for addressing messaging components; to use it
with a given messaging protocol, a protocol mapping must be defined.
This specification provides a mapping to AMQP 0-10. At this point,
AMQP 1.0 is not yet final, but we expect that applications written
using the High Level Client API can be migrated to AMQP 1.0 with
minimal changes, and applications that do not need to configure
messaging components can be used without change.
</para>
<para>The Qpid High Level Client API programming model is very
similar to the Java JMS programming model. Here are the most
important classes in the high level programming model:
</para>
<itemizedlist>
<listitem><para>A <emphasis>connection</emphasis> represents a
network connection. The parameters for the network connection are
specified using a URL-based syntax when the connection is
opened.</para></listitem>
<listitem><para>A <emphasis>session</emphasis> represents the
interface between a <emphasis>messaging client</emphasis> and a
<emphasis>messaging broker</emphasis>. A session is created by a
connection.</para></listitem>
<listitem><para>An <emphasis>address</emphasis> is a string that
represents a node on a messaging broker. In the AMQP 0-10 mapping,
an address represents either an exchange or a queue. In the AMQP
1.0 mapping, an address will represent an AMQP 1.0 node. Most
addresses are simple names. An extended address can also specify
options.</para></listitem>
<listitem><para>A <emphasis>sender</emphasis> is a messaging
client that sends <emphasis>message</emphasis>s to a destination
on a <emphasis>messaging broker</emphasis>. A sender is created by
a session.</para></listitem>
<listitem><para>A <emphasis>receiver</emphasis> is a messaging
client that receives <emphasis>message</emphasis>s from a
source on a <emphasis>Messaging Broker</emphasis>. A Receiver
is created by a Session.</para></listitem>
</itemizedlist>
<section>
<title>A Simple Sender and Receiver in C++</title>
<para>This section shows the code for two programs. One is a
simple sender, the other is a simple receiver.</para>
<section>
<title>Connections and Sessions</title>
<para>Both of these programs use the same skeleton, which includes
the headers that define the Connection, Message, Receiver, Sender,
and Session objects. The code in <methodname>main()</methodname>
opens a connection using a URL that identifies a messaging broker,
creates a session, and catches any errors that occur during
messaging:</para>
<programlisting><![CDATA[
#include <qpid/messaging/Connection.h>
#include <qpid/messaging/Message.h>
#include <qpid/messaging/Receiver.h>
#include <qpid/messaging/Sender.h>
#include <qpid/messaging/Session.h>
#include <iostream>
using namespace qpid::messaging;
int main() {
Connection connection;
try {
connection.open("amqp:tcp:127.0.0.1:5672");
Session session = connection.newSession();
/* #### Main body of messaging code goes here #### */
connection.close();
return 0;
} catch(const std::exception& error) {
std::cout << error.what() << std::endl;
connection.close();
}
return 1;
}]]></programlisting>
</section>
<section>
<title>A Message Sender</title>
<para>The sender program creates a Sender object that sends messages
to <varname>message_queue</varname>, which happens to be a queue on
on AMQP 0-10 messaging broker:</para>
<programlisting><![CDATA[
Sender sender = session.createSender("message_queue");
for (int i=0; i<5; i++) {
std::stringstream content;
content << "Message " << i;
sender.send(Message(content.str()));
}
sender.close();
}]]></programlisting>
</section>
<section>
<title>A Message Receiver</title>
<para>The receiver program creates a Receiver object, reads messages
from <varname>message_queue</varname>, acknowledging them so the
messaging broker knows they have been received and can be safely
removed from the queue, and prints them:</para>
<programlisting><![CDATA[
Receiver receiver = session.createReceiver("message_queue");
Message message;
int timeout = 1000; /* in milliseconds */
while (receiver.fetch(message, timeout)) {
std::cout << message.getContent();
session.acknowledge();
}
receiver.close();
]]></programlisting>
<para>The <methodname>Receiver::fetch()</methodname> method can be
used with or without a timeout. In either case, it is guaranteed to
receive any messages on the queue. Here, the timeout is used in
case <command>sender</command> is publishing at the same time
message are being read.</para>
</section>
</section>
<section>
<title>Addresses</title>
<para>As we have seen, an address is a string that identifies
objects on the messaging broker. There are two kinds of
addresses. A <firstterm>simple address</firstterm> is a name. An
<firstterm>extended address</firstterm> can also have a
<firstterm>subject</firstterm> and
<firstterm>options</firstterm>.</para>
<para>The syntax for an address is:</para>
<programlisting><![CDATA[
address ::= <name> [ / <subject> ] [ ; <options> ]
options ::= { <key> : <value>, ... }
]]></programlisting>
<para>Names, subjects, and keys are strings.</para>
<para>Values can be numbers, strings (with optional single or double quotes), maps, or lists.</para>
<para>In most cases, queues, bindings, and exchanges are
configured externally with management tools. Qpid High Level API
clients send to and receive from these queues and exchanges.</para>
<para>In AMQP 0-10, messages are sent to exchanges, and received
from queues. The Qpid High Level Client API allows programs to
send to or receive from any node. To make this possible, the
mapping defines the semantics of sending and receiving for all
AMQP 0-10 exchange types and queues as follows:
<itemizedlist>
<listitem><para>When a Sender sends a message to an exchange,
the transfer destination is set to the exchange name, and the
routing key is set to the value of the address
subject.</para></listitem>
<listitem><para>When a Receiver receives messages from an
exchange, the API automatically creates a subscription queue and
binds it to the exchange. If the address contains a subject,
then it is used as the binding key. If the address does not
contain a subject, then the binding key depends on the exchange
type:
<itemizedlist>
<listitem><para>topic exchange: wildcard match</para></listitem>
<listitem><para>direct exchange: error — the address must specify a subject</para></listitem>
<listitem><para>fanout: none</para></listitem>
</itemizedlist></para>
<para>The subscription queue's <varname>durability</varname>
and <varname>autodelete</varname> properties can be set
using options.</para>
</listitem>
<listitem><para>When a Sender sends a message to a queue, the
message is sent to the AQMP 0-10 default queue, using the name
of teh queue as the routing key.</para></listitem>
<listitem><para>When a Receiver receives messages from a queue,
it is treated as a normal AMQP 0-10 queue subscription. The
<varname>accept-mode</varname> property can be set using
options.</para></listitem>
</itemizedlist>
</para>
<para>The following sections describe the various kinds of
addresses in detail. The examples in these sections use the
<command>qpid-config</command> utility to configure AMQP 0-10
queues and exchanges, send messages using
<command>drain</command>, and receive messages using
<command>spout</command>. The source code for
<command>drain</command> and <command>spout</command> is available
in both C++ and Python, and can be found in the examples directory
for each language. These programs can use any address as a source
or a destination, and have many command line options to configure
behavior—use the <command>-h</command> option for
documentation on these options.</para>
<section>
<title>Simple Addresses</title>
<para>If an address contains only a name, it resolves to a named
node. On AMQP 0-10, a named node maps to a queue or an exchange with
the same name.
<note>
<para>Address resolution is not yet well-defined if a queue and
an exchange have the same name. This is a known problem, and is
being resolved.</para>
</note></para>
<example>
<title>Simple Addresses</title>
<para>Create a queue with qpid-config, send a message using
spout, and read it using drain:</para>
<programlisting>
$ qpid-config add queue hello-world
$ ./spout -a hello-world
$ ./drain -a hello-world
Message(properties={spout-id:c877e622-d57b-4df2-bf3e-6014c68da0ea:0}, content='')
</programlisting>
<para>Exchanges and queues are addressed in exactly the same way
in the Qpid High Level Client API. If we delete the queue named
<literal>hello-world</literal> and create an exchange with the
same name, we can write to and read from the exchange in the
same way as for the queue:</para>
<programlisting>
$ qpid-config del queue hello-world
$ qpid-config add exchange topic hello-world
$ ./spout -a hello-world
$ ./drain -a hello-world
$
</programlisting>
<para>In AMQP 0-10, exchanges discard messages if ####</para>
<!--
SH: qpid-config add queue hello-world
- once created, an address simply refers to them by name
SH: spout -c 10 hello-world
SH: drain hello-world
SH: qpid-config
+ this works the same for exchanges
SH: qpid-config del queue hello-world
SH: qpid-config add exchange topic hello-world
SH: spout -c 10 hello-world
SH: drain hello-world
- client code remains exactly the same, but routing behavior
changes
- exchanges drop messages if nobody is listening, so we need to
start drain first
- drain will exit immediately if the source is empty (note that
this is actually a semantic guarantee provided by the API, we
know for a fact that the source is empty when drain/fetch
reports it, no fudge factor timeout is required [this assumes
nobody is concurrently publishing of course])
- drain -f invokes blocking fetch (you could use a timeout here also)
SH1: drain -f hello-world
SH: spout -c 10 hello-world
SH2: drain -f hello-world
SH: spout -c 10 hello-world
- multiple drains will get all messages because this is an
exchange
- for a queue messages will be load balanced between drains
SH: qpid-config add queue hello-queue
SH1: drain -f hello-world
SH2: drain -f hello-world
SH: spout -c 10 hello-world
+ an address is resolved to a node
- the API internals will adjust how they send/receive based on
the type of node
- in AMQP 0-10 exchanges and queues are the two standard
categories of nodes
- in JMS these are called topics and queues
- we use the topic terminology to be consistent with JMS (note
that when used in this sense topic refers to any exchange, not
just a topic exchange)
- we'll cover the precise details of the mapping later
-->
</example>
</section>
<section>
<title>Subjects</title>
<para>
A simple name with a subject will also resolve to a node, but the
presence of the subject will cause a sender using this address to
set the subject on outgoing messages, and receivers to filter based
on the subject:
my-queue-or-topic/my-subject
A subject pattern can be used and will cause filtering if used by
the receiver. If used for a sender, the literal value gets set as
the subject::
my-queue-or-topic/my-*
</para>
</section>
<section>
<title>Options</title>
<!--
In all the above cases, the address is resolved to an existing node.
If you want the node to be auto-created, then you can do the
following. By default nonexistent nodes are assumed to be queues::
my-queue; {create: always}
You can customize the properties of the queue::
my-queue; {create: always, node-properties: {durable: True}}
You can create a topic instead if you want::
my-queue; {create: always, node-properties: {type: topic}}
You can assert that the address resolves to a node with particular
properties::
my-transient-topic; {
assert: always,
node-properties: {
type: topic,
durable: False
}
}
; {create: always}'
spout 'hello-whirled; {assert: always, node-properties: {type: topic}}'
SH: spout 'small-world; {create: always, node-properties: {type: topic}}'
SH: spout 'cruel-world; {create: always, node-properties: {type: topic, x-properties: {type: direct}}}'
SH1: drain -f 'world-news; {create: always, node-properties: {x-properties: {bindings: ["small-world/news.#", "hello-world/news.#", "cruel-world/news"]}}}'
SH: spout small-world/news.local
-->
<!--
#### What is the syntax for names?
-->
<!--
- we'll cover the precise details of the mapping later
- an extended address can include a subject and options (we'll get to the options later)
+ subject is a standard message property
- subjects classify messages
+ when you specify a subject in a target address, that value
becomes the default subject property on outgoing Messages (this
can be overriden by setting the subject explicitly on each
messages)
- extended address options adjust the semantics of senders/receivers
+ some options control the resolution process:
- assert/create/delete, node-properties
- more on this later
+ some options control message transfer semantics:
- reliability: unreliable/at-least-once/at-most-once/exactly-once
- mode: browse/consume (only for receivers)
-->
<!--
<rhs> POLICIES = Values("always", "sender", "receiver", "never")
<rhs> RELIABILITY = Values("unreliable", "at-most-once", "at-least-once",
<rhs> "exactly-once")
<rhs> DECLARE = Map({}, restricted=False)
<rhs> BINDINGS = List(Map({
<rhs> "exchange": Types(basestring),
<rhs> "queue": Types(basestring),
<rhs> "key": Types(basestring),
####### Is this ignored for sending in the AMQP 0-10 binding?
<rhs> "arguments": Map({}, restricted=False)
<rhs> }))
<rhs> COMMON_OPTS = {
<rhs> "create": POLICIES,
<rhs> "delete": POLICIES,
<rhs> "assert": POLICIES,
<rhs> "node": Map({
<rhs> "type": Values("queue", "topic"),
<rhs> "durable": Types(bool),
<rhs> "x-declare": DECLARE,
<rhs> "x-bindings": BINDINGS
<rhs> }),
<rhs> "link": Map({
<rhs> "name": Types(basestring),
<rhs> "durable": Types(bool),
<rhs> "reliability": RELIABILITY,
<rhs> "x-declare": DECLARE,
<rhs> "x-bindings": BINDINGS,
<rhs> "x-subscribe": Map({}, restricted=False)
<rhs> })
<rhs> }
<rhs> RECEIVE_MODES = Values("browse", "consume")
<rhs> SOURCE_OPTS = COMMON_OPTS.copy()
<rhs> SOURCE_OPTS.update({
<rhs> "mode": RECEIVE_MODES
<rhs> })
<rhs> TARGET_OPTS = COMMON_OPTS.copy()
-->
<para></para>
</section>
</section>
<section>
<title>Messaging Properties</title>
<para>This section shows how Qpid High Level Client API message
properties are mapped to AMQP message properties and delivery
properties.</para>
<para>In the following table, <varname>msg</varname> refers to the
Message class defined in the High Level Client API,
<varname>mp</varname> refers to an AMQP 0-10
<varname>message-properties</varname> struct, and
<varname>dp</varname> refers to an AMQP 0-10
<varname>delivery-properties</varname> struct.</para>
<table>
<title>Mapping to AMQP 0-10 Message Properties</title>
<tgroup cols="3">
<thead>
<row>
<entry>Python API</entry>
<entry>C++ API</entry>
<entry>AMQP 0-10 Property</entry>
</row>
</thead>
<tbody>
<row>
<entry>msg.id</entry><entry>msg.{get,set}MessageId()</entry><entry>mp.message_id</entry>
</row>
<row>
<entry>msg.to</entry><entry>- -</entry><entry>mp.application_headers["qpid.to"]</entry>
</row>
<row>
<entry>msg.subject</entry><entry>msg.{get,set}Subject()</entry><entry>mp.application_headers["qpid.subject"]</entry>
</row>
<row>
<entry>msg.user_id</entry><entry>msg.{get,set}UserId()</entry><entry>mp.user_id</entry>
</row>
<row>
<entry>msg.reply_to</entry><entry>msg.{get,set}ReplyTo()</entry><entry>mp.reply_to<footnote><para>The reply_to is converted from the protocol representation into an address.</para></footnote></entry>
</row>
<row>
<entry>msg.correlation_id</entry><entry>msg.{get,set}CorrelationId()</entry><entry>mp.correlation_id</entry>
</row>
<row>
<entry>msg.durable</entry><entry>msg.{get,set}Durable()</entry><entry>dp.delivery_mode == delivery_mode.persistent<footnote><para>Note that msg.durable is a boolean, not an enum.</para></footnote></entry>
</row>
<row>
<entry>msg.priority</entry><entry>msg.{get,set}Priority()</entry><entry>dp.priority</entry>
</row>
<row>
<entry>msg.ttl</entry><entry>msg.{get,set}Ttl()</entry><entry>dp.ttl</entry>
</row>
<row>
<entry>msg.redelivered</entry><entry>msg.isRedelivered()</entry><entry>dp.redelivered</entry>
</row>
<row><entry>msg.properties</entry><entry>msg.{get,set}Headers()</entry><entry>mp.application_headers</entry>
</row>
<row>
<entry>msg.content_type</entry><entry>msg.{get,set}ContentType()</entry><entry>mp.content_type</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
</chapter>
<!--
* qpid.messaging.address
* qpid.messaging.constants
* qpid.messaging.driver
* qpid.messaging.endpoints: A candidate high level messaging API for python.
* qpid.messaging.exceptions
* qpid.messaging.message
* message hierarchy
* qpid.messaging.util: Add-on utilities for the qpid.messaging API.
-->
<!--
<section>
<title>Example Programs</title>
</section>
</chapter>
-->
<!--
- drain and spout are basically command line versions of the API
+ drain is a receiver that operates on an any message source
- drains all available messages from a source and then exits
- behavior can be further controlled with options
SH: drain -h
+ spout is a sender that sends to any message target
- generates a message and sends it to a target
- message content can be controlled with options
SH: spout -h
- source and target are specified as addresses
+ addresses are symetric (sort of), any target is a source, but not
all sources are targets, e.g. sources might add filtering
- an address is just a name
+ the name is resolved to a broker entity prior to sending/receiving
- spout/drain to a nonexistent address is an error
SH: spout hello-world
+ the same error will occur when using the API to create
senders/receivers
+ normally broker entities are created outside the API
SH: qpid-config add queue hello-world
- once created, an address simply refers to them by name
SH: spout -c 10 hello-world
SH: drain hello-world
SH: qpid-config
+ this works the same for exchanges
SH: qpid-config del queue hello-world
SH: qpid-config add exchange topic hello-world
SH: spout -c 10 hello-world
SH: drain hello-world
- client code remains exactly the same, but routing behavior
changes
- exchanges drop messages if nobody is listening, so we need to
start drain first
- drain will exit immediately if the source is empty (note that
this is actually a semantic guarantee provided by the API, we
know for a fact that the source is empty when drain/fetch
reports it, no fudge factor timeout is required [this assumes
nobody is concurrently publishing of course])
- drain -f invokes blocking fetch (you could use a timeout here also)
SH1: drain -f hello-world
SH: spout -c 10 hello-world
SH2: drain -f hello-world
SH: spout -c 10 hello-world
- multiple drains will get all messages because this is an
exchange
- for a queue messages will be load balanced between drains
SH: qpid-config add queue hello-queue
SH1: drain -f hello-world
SH2: drain -f hello-world
SH: spout -c 10 hello-world
+ an address is resolved to a node
- the API internals will adjust how they send/receive based on
the type of node
- in AMQP 0-10 exchanges and queues are the two standard
categories of nodes
- in JMS these are called topics and queues
- we use the topic terminology to be consistent with JMS (note
that when used in this sense topic refers to any exchange, not
just a topic exchange)
- we'll cover the precise details of the mapping later
- an extended address can include a subject and options (we'll get to the options later)
+ subject is a standard message property
- subjects classify messages
+ when you specify a subject in a target address, that value
becomes the default subject property on outgoing Messages (this
can be overriden by setting the subject explicitly on each
messages)
SH1: drain -f hello-world
SH: spout hello-world/how.are.you
+ when you specify a subject in a source address, the value is used
to filter messages from the source based on matching the value
against available message subjects
SH2: drain -f hello-world/how.are.you
SH: spout hello-world
SH: spout hello-world/how.are.you
SH2: drain -f hello-world/how.#
SH: spout hello-world
SH: spout hello-world/how.are.you
SH: spout hello-world/how.cruel.you.are
- the pattern matching algorithm depends on the type of broker
entity the address resolves to (e.g. fanout vs topic vs direct)
- note that this doesn't yet work with queues because we can only
filter going into the queue at present (i.e. no server side
selectors)
- extended address options adjust the semantics of senders/receivers
+ some options control the resolution process:
- assert/create/delete, node-properties
- more on this later
+ some options control message transfer semantics:
- reliability: unreliable/at-least-once/at-most-once/exactly-once
- mode: browse/consume (only for receivers)
SH: spout -c 10 hello-queue
SH: drain 'hello-queue; {mode: browse}'
SH: drain 'hello-queue; {mode: browse}'
SH: drain 'hello-queue; {mode: consume}'
SH: drain 'hello-queue; {mode: consume}'
- durable: True/False (currently only for receivers from topics/exchanges)
SH: # durable demo???
- no-local: True/False (only for receivers from topics/exchanges)
SH: #- filter: XXX
- API mapping to AMQP 0-10
+ for 0-10 an address is resolved to a queue and/or exchange by
querying for them both by name
- don't ask the obvious question
+ message properties are NOT directly mapped to/from the protocol,
reference the following table for translation
-->
<!--
Python API C++ API AMQP 0-10 Protocol Mapping
|=========================================================================================
<row>
<entry>msg.id </entry><entry>msg.{get,set}MessageId()</entry><entry>mp.message_id
<row>
<entry>msg.to </entry><entry>- - </entry><entry>mp.application_headers["qpid.to"]
<row>
<entry>msg.subject </entry><entry>msg.{get,set}Subject() </entry><entry>mp.application_headers["qpid.subject"]
<row>
<entry>msg.user_id </entry><entry>msg.{get,set}UserId() </entry><entry>mp.user_id
<row>
<entry>msg.reply_to </entry><entry>msg.{get,set}ReplyTo() </entry><entry>mp.reply_to *
<row>
<entry>msg.correlation_id | msg.{get,set}CorrelationId() | mp.correlation_id
<row>
<entry>msg.durable </entry><entry>msg.{get,set}Durable() </entry><entry>dp.delivery_mode == delivery_mode.persistent **
<row>
<entry>msg.priority </entry><entry>msg.{get,set}Priority() </entry><entry>dp.priority
<row>
<entry>msg.ttl </entry><entry>msg.{get,set}Ttl() </entry><entry>dp.ttl
<row>
<entry>msg.redelivered | msg.isRedelivered() </entry><entry>dp.redelivered
<row>
<entry>msg.properties</entry><entry>msg.{get,set}Headers() </entry><entry>mp.application_headers
<row>
<entry>msg.content_type | msg.{get,set}ContentType() | mp.content_type
msg: Message class in API
mp: message-properties protocol struct
dp: delivery-properties protocol struct
*: the reply_to is converted from the protocol representation into an address
**: note that msg.durable is a boolean, not an enum
+ recall that sending and receiving is adjusted based on the node
type, there are four basic cases to cover:
- sending to an exchange
+ the transfer destination is set to the exchange name
+ the routing key is set to the value of the subject (copied from the subject property)
- receving from an exchange
+ a subscription queue is automatically created and bound to the exchange
- durability of subscription queue is set based on durable address option
- auto-delete is set based on reliability address option
+ if no subject is specified, then a default binding key is
chosen based on the exchange type:
- topic: wildcard match
- direct: *error*
- fanout: N/A
+ if a subject is specified, it is used as the binding key
- sending to a queue
+ the transfer destination is set to the default/no-name exchange
+ the routing key is set to the queue name
- receiving from a queue
+ trivially maps to a normal subscribe
- accept-mode for receiving (from regular or subscription queue)
is set based on reliability options
- create/delete/assert options
+ these options can all be set to one of: sender, receiver, always, never
- the value controls when the option is in effect: when used as a
sender target, when used as a receiver source, always, or never
+ these options specify policies that can be customized via the
additional node-properties option
+ by default it's an error when resolution fails, options can adjust this
- assert makes the resolution process more picky by matching the
resolved node against the specified node-properties
- if the node doesn't exist, and the create option is in effect
the node will be created with the specified node-properties (we
default to a queue if no properties are present)
SH: spout hello-whirled
SH: spout 'hello-whirled; {create: always}'
SH: qpid-config queues
+ if the delete option is in effect, then the node will be deleted
when the sender and/or receiver is closed
- note that this option needs broker support to be safely used
outside of very simple scenarios
+ node-properties:
- type: topic or queue
- durable: True/False
- x-properties: unrestricted map
+ type: (specifies the exchange type when the address type is a topic)
+ bindings: ["exchange/binding-key", ...] (only works for queues)
+ anything else that matches a protocol field gets set in the
exchange/queue declare
+ anything else that does *not* match a protocol field gets
added to the arguments map in the exchange/queue declare
SH: #spout 'hello-whirled; {assert: always, node-properties: {type: topic}}'
SH: spout 'small-world; {create: always, node-properties: {type: topic}}'
SH: qpid-config exchanges
SH: spout 'cruel-world; {create: always, node-properties: {type: topic, x-properties: {type: direct}}}'
SH: qpid-config exchanges
SH1: drain -f 'world-news; {create: always, node-properties: {x-properties: {bindings: ["small-world/news.#", "hello-world/news.#", "cruel-world/news"]}}}'
SH: qpid-config queues -b
SH: spout small-world/news.local
SH: spout hello-world/news.friendly
SH: spout cruel-world/news
- connections can be configured to automatically reconnect, this
behavior is controlled by the following options
+ reconnect: True/False (enables/disables reconnect entirely)
+ reconnect_timeout: number of seconds (give up and report failure after specified time)
+ reconnect_limit: n (give up and report failure after specified number of attempts)
+ reconnect_interval_min: number of seconds (initial delay between failed reconnection attempts)
+ reconnect_interval_max: number of seconds (maximum delay between failed reconnection attempts)
+ reconnect_interval: shorthand for setting the same reconnect_interval_min/max
+ first reconnect attempt is made immediately, if that fails an
exponentially increasing delay controlled by above parameters is
introduced
SH1: drain -rf amq.topic
TODO:
- don't forget to remove pattern munging from python client!
- get more advanced filtering in python (XML exchange, etc)
- define behavior if both exchange and queue exist
- figure out how to add passthrough options to other things like
binding and subscription, maybe use this for accessing things like
the xml exchange
-->
|