Interact with LavinMQ and explore AMQP concepts.
This will create a user and vhost in the broker.
When you click the button below, it will populate queues named "<city>" (for
the cities vilnius and kaunas) with
some available taxis.
| Taxi | Price | To | From | Group Name |
|---|
TaxiHub is a fictional ride-hailing startup operating in Vilnius and Kaunas. You're the new backend engineer, and the product team needs a booking pipeline and a driver-comms system glued together using LavinMQ. Each task adds one small microservice.
First, head to the Register tab and pick a name — this creates your user and vhost on the broker. Use that same name in the AMQP URL below (user, password, and vhost are all the same value).
AMQP URL
amqps://<name>:<name>@devopspro.lmq.cloudamqp.com/<name>
Management UI: devopspro.lmq.cloudamqp.com — use this throughout to inspect queues, exchanges, bindings, and messages.
Client libraries: any AMQP 0.9.1 client works —
bunny (Ruby), pika (Python), amqp-client.js (Node),
amqp-client.cr (Crystal), amqp091-go (Go),
RabbitMQ.Client (.NET), and so on.
Task 1 — a 3-step booking pipeline: receive a request → match a taxi
→ price the ride.
Task 2 — a driver-comms broadcaster: route fleet notifications differently
depending on how urgent and how targeted they are (everyone / one city / jump the queue).
Goal. Receive a booking request, compute the route distance, forward it on.
You'll learn. Connecting to LavinMQ, declaring a queue, subscribing, publishing to the default exchange by queue name, and acknowledging messages.
Steps.
booking_requests queue.from (only vilnius and
kaunas are supported) and to.
bookings queue.Try it. Use the Book Taxi button in the Tools tab to send an input message.
Input (booking_requests queue):
{"from": "vilnius", "to": "stockholm"}
Output (bookings queue):
{"from": "vilnius", "to": "stockholm", "distance": "5000"}
Done when. Every Book Taxi click
produces a new message on bookings in the management UI.
Goal. For each booking, claim the next available taxi from that city.
You'll learn. Pulling a single message with basic_get (vs.
subscribing), and handling "no work available" gracefully.
Steps.
bookings queue.from city and pull one message from the queue named after it
— each city has its own queue, named simply vilnius or
kaunas.
matched_taxis.
Setup. Use the Populate Taxis button in the Tools tab to fill each city queue with available taxis.
Heads up. What should happen if the city queue is empty? Two reasonable answers: drop the booking with a log, or requeue it and retry later. Either is fine — just be explicit about the choice.
Input (bookings queue):
{"from": "vilnius", "to": "stockholm", "distance": "5000"}
Input (city queue vilnius or kaunas, populated by the Populate Taxis button):
{"taxi": "KFT822"}
Output (matched_taxis queue):
{"from": "vilnius", "to": "stockholm", "distance": "5000", "taxi": "KFT822"}
Done when. Each booking consumes exactly one taxi message and produces one
matched_taxis message.
Goal. Attach a price and finalise the booking.
You'll learn. Chaining services through queues — the value of small, single-purpose microservices.
Steps.
matched_taxis.rand, or
base + distance * rate).
confirmed_bookings.matched_taxis queue):
{"from": "vilnius", "to": "stockholm", "distance": "5000", "taxi": "KFT822"}
Output (confirmed_bookings queue):
{"from": "vilnius", "to": "stockholm", "distance": "5000", "taxi": "KFT822", "price": "1337"}
Done when. Confirmed bookings appear in the Confirmed Taxis table in the Tools tab.
You've built TaxiHub's full booking pipeline — request, match, price. Verify the end-to-end flow in the Confirmed Taxis section of the Tools tab.
TaxiHub now needs a way for HQ to talk to drivers. Different messages need different reach: some go to everyone, some go to one city, and some need to jump the queue.
Use the Send Notifications form in the Tools tab to generate input messages for these tasks.
Goal. A "free fika at HQ" message should reach every taxi, regardless of city.
You'll learn. Fanout exchanges (route to all bound queues, ignore routing key), durable exchanges, and bulk-binding queues at startup.
Steps.
<city>_<plate> (e.g. vilnius_KFT822).
news and bind every taxi queue to it.
notifications; when status == "news",
publish {"info": <message>} to the news exchange.
Reflection. Should the news exchange be durable? What breaks if
it isn't and the broker restarts?
notifications queue):
{"city": "vilnius", "message": "Free fika at HQ", "status": "news"}
Output (fanout exchange news):
{"info": "Free fika at HQ"}
Done when. The same message appears in every taxi queue in the management UI.
Goal. "More customers needed downtown" should reach only that city's drivers.
You'll learn. Topic exchanges, routing keys, and binding queues to specific keys.
Steps.
alerts.vilnius_* queues use routing key vilnius, and likewise
for kaunas).
notifications; when status == "alert",
publish {"info": <message>} to alerts using the
city as the routing key.
Heads up. If your 2a service is still running, both will pull from
notifications and silently drop each other's messages (competing
consumers). Stop 2a first, or merge both handlers into one service.
notifications queue):
{"city": "vilnius", "message": "More customers needed downtown", "status": "alert"}
Output (topic exchange alerts, routing key
<city>):
{"info": "More customers needed downtown"}
Done when. Only that city's taxi queues receive the message — the other city's queues stay empty.
Goal. "Road blocked, reroute now" should land at the front of each driver's queue, ahead of normal alerts already waiting.
You'll learn. Queue arguments (x-max-priority), the publish-time
priority property, and why queue arguments are immutable after creation.
Steps.
x-max-priority: 255 and observe what happens — you'll get
PRECONDITION_FAILED (406). Queue arguments can't be changed after a
queue is created.
<city>_<plate> queue and recreate it with
x-max-priority: 255. Valid range is 0–255; higher numbers mean
sooner delivery.
alerts topic exchange by city.notifications; when status == "crisis",
publish {"info": <message>} to alerts with routing
key <city> and message property priority: 255.
Heads up. The 406 closes the channel it was sent on. Use a throwaway channel for the delete-and-recreate dance so your main consumer channel survives.
Input (notifications queue):
{"city": "vilnius", "message": "Crash blocking Gedimino Ave", "status": "crisis"}
Output (topic exchange alerts, routing key
<city>, priority 255):
{"info": "Crash blocking Gedimino Ave"}
Done when. Send a normal alert and then a crisis to the same city — the crisis message sits ahead of the alert in the queue (visible via the management UI's Get messages action on a taxi queue).