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.
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()
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))
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')
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
| Address | What 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.
| Outcome | What 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
| User | May |
|---|---|
| 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.