sondahub

sondahub / AMQP 1.0 test broker

AMQP 1.0 test broker

AMQP 1.0 on the same broker and the same port as AMQP 0-9-1, the way RabbitMQ 4 serves both: SASL, sessions, links with credit and settlement, RabbitMQ’s /exchanges and /queues addresses, queues already filling with the hub’s live activity, orders that move and an rpc queue that answers. Over TCP through a small bridge, or straight over WebSocket.

Free, nothing to install but the bridge — and not even that over WebSocket.

Connect

Over TCP
through the bridge: node bridge.mjs amqp, then amqp://guest:guest@localhost:5772
WebSocket
wss://api.sondahub.com/amqp
Subprotocol
amqp
SASL
PLAIN (guest/guest, sonda/sondahub, viewer/viewer) or ANONYMOUS
Open
container-id sondahub, max-frame-size 131,072, idle-time-out 60 s

The same broker as AMQP 0-9-1, on the same port: the bridge listens on 5772 and the protocol header decides. Queues are already filling — /queues/store, /queues/fleet, /queues/bank, /queues/social, /queues/helpdesk, /queues/flights, /queues/identity hold each API’s live activity, the last minute there from the start — and /queues/orders and /queues/rpc answer.

Python (Qpid Proton)
from proton import Message
from proton.utils import BlockingConnection

conn = BlockingConnection("amqp://guest:guest@localhost:5772", allowed_mechs="PLAIN")
receiver = conn.create_receiver("/queues/fleet")
msg = receiver.receive(timeout=5)
print(msg.annotations, msg.body)
receiver.accept()
sender = conn.create_sender("/queues/orders")
sender.send(Message(body='{"customer_id": 7, "total": 42.5}', content_type="application/json"))
conn.close()
Node (rhea)
import rhea from 'rhea'

const conn = rhea.connect({ host: 'localhost', port: 5772, username: 'guest', password: 'guest' })
conn.open_receiver('/queues/store')
conn.on('message', (ctx) => console.log(ctx.message.message_annotations['x-routing-key'], ctx.message.body))
Browser (rhea over WebSocket, no bridge)
const ws = rhea.websocket_connect(WebSocket)
const conn = rhea.connect({ connection_details: ws('wss://api.sondahub.com/amqp', ['amqp']), username: 'guest', password: 'guest' })
conn.open_receiver('/queues/bank')
.NET (AMQP.Net Lite)
var conn = await Connection.Factory.CreateAsync(new Address("amqp://guest:guest@localhost:5772"));
var session = new Session(conn);
var receiver = new ReceiverLink(session, "fleet-reader", "/queues/fleet");
var msg = await receiver.ReceiveAsync(TimeSpan.FromSeconds(5));
receiver.Accept(msg);

In LockFlare Sonda: an AMQP 1.0 item pointed at localhost:5772 as guest/guest, with the bridge running — 5772, not 5672 — reading /queues/fleet, or sending to /queues/orders.

Addresses

AddressWhat it does
/exchanges/:exchange/:routing-key
target
Publishes to the exchange with that routing key — /exchanges/amq.topic/store.orders.
/exchanges/:exchange
target
Publishes to the exchange with each message’s subject as the routing key.
/queues/:queue
target or source
Sends to the queue (through the default exchange), or reads from it — /queues/fleet, /queues/orders, /queues/rpc.
(none)
target
The anonymous relay: each message goes where its to property says, in one of the forms above.
dynamic
source
A queue of the link’s own, made for it and gone with it; the attach answers with its address. For replies.
/topic/:key, /exchange/:x/:key, /queue/:q, /amq/queue/:q
the older forms
RabbitMQ’s first AMQP 1.0 addresses still work: a /topic or /exchange source reads through a queue of the link’s own bound with the key; /queue declares the queue when it is not there.

A missing exchange or queue refuses the link with amqp:not-found — an attach with a null terminus, then a detach with the error, as the spec has it.

Messages and settlement

Links take credit as the spec gives it: the broker grants a sender 100 at a time and tops it up; a receiver gets what its credit allows, and drain uses up the rest at once. Messages go settled or unsettled as the link’s snd-settle-mode says; big ones cross in several transfer frames, up to 4 MB a message. Each message a receiver gets carries x-exchange and x-routing-key message annotations; one that came over AMQP 1.0 keeps its own properties, application properties and body as they were sent, and one from AMQP 0-9-1 gets its properties and headers as properties and application properties, its body as a data section.

OutcomeWhat it means
accepted
a message in
It reached a queue.
released
a message in
It reached no queue — nothing is bound there for that key, as RabbitMQ settles it.
rejected
a message in
A queue refused it (reject-publish), the to address was not one the broker takes, or the message did not decode — with the error condition.
accepted
a message out
Done: it leaves the queue.
released
a message out
Back to the queue, to come again (delivery-count 1).
modified
a message out
Back to the queue — or, with undeliverable-here, dead-lettered like rejected.
rejected
a message out
Dead-lettered through the queue’s dead-letter exchange, or dropped when it has none.

RPC

Attach a dynamic receiver, send {"method":"store.getProduct","params":{"id":1}} to /queues/rpc with reply-to set to the address it was given and a correlation-id, and the answer arrives on it: {"result":…} with your correlation-id — every call JSON-RPC makes. Orders sent to /queues/orders move on amq.topic as store.orders: paid, shipped, delivered.

Users

UserMay
guest
password guest
Everything.
sonda
password sondahub
Everything.
viewer
password viewer
Reads. A sending link is refused with amqp:unauthorized-access.
ANONYMOUS
SASL
Signs in as guest.
Anyone else
or a wrong password
sasl-outcome auth, and the connection closes.

Questions

Is this the same broker as AMQP 0-9-1?

Yes — the same port, the same exchanges and queues. The broker reads the protocol header a client sends and answers in AMQP 1.0 or 0-9-1, as RabbitMQ 4 does on 5672, so a message an AMQP 1.0 client sends to /queues/orders is read by a 0-9-1 client, and the other way round. Properties, application properties and headers carry across. The 0-9-1 side.

Do I need the bridge?

Over TCP, yes: node bridge.mjs amqp lends the broker 5772 on your computer. AMQP 1.0 has a WebSocket binding too, so a client that speaks it — rhea in the browser, say — connects to wss://api.sondahub.com/amqp with the subprotocol amqp and needs no bridge; each such connection is a broker of its own.

What is not offered?

Transactions (a coordinator link is refused with amqp:not-implemented), RabbitMQ 4’s /management node, filters on sources, link recovery with unsettled state, and TLS. Topology comes from the hub’s queues, the older address forms, or an AMQP 0-9-1 client on the same broker.