add notifier
This commit is contained in:
@@ -104,47 +104,47 @@ Success check:
|
|||||||
|
|
||||||
## Step 4: Worker (35 min)
|
## Step 4: Worker (35 min)
|
||||||
|
|
||||||
- [ ] `worker.py` consumes from `orders.q` with manual ACK.
|
- [x] `worker.py` consumes from `orders.q` with manual ACK.
|
||||||
- [ ] For each message:
|
- [x] For each message:
|
||||||
- [ ] Parse JSON
|
- [x] Parse JSON
|
||||||
- [ ] Simulate processing (`sleep(1)`)
|
- [x] Simulate processing (`sleep(1)`)
|
||||||
- [ ] If `should_fail` and `retry_count < 2`, republish same order with `retry_count + 1` to `order.created`, ACK original.
|
- [x] If `should_fail` and `retry_count < 2`, republish same order with `retry_count + 1` to `order.created`, ACK original.
|
||||||
- [ ] If `should_fail` and `retry_count >= 2`, publish to `order.failed`, ACK original.
|
- [x] If `should_fail` and `retry_count >= 2`, publish to `order.failed`, ACK original.
|
||||||
- [ ] Else publish to `order.processed`, ACK original.
|
- [x] Else publish to `order.processed`, ACK original.
|
||||||
|
|
||||||
Important:
|
Important:
|
||||||
|
|
||||||
- [ ] Set `prefetch_count=1`.
|
- [x] Set `prefetch_count=1`.
|
||||||
- [ ] Use persistent publish for all outgoing messages.
|
- [x] Use persistent publish for all outgoing messages.
|
||||||
|
|
||||||
Success check:
|
Success check:
|
||||||
|
|
||||||
- [ ] You see logs for retries and final outcomes.
|
- [x] You see logs for retries and final outcomes.
|
||||||
|
|
||||||
## Step 5: Notifier (15 min)
|
## Step 5: Notifier (15 min)
|
||||||
|
|
||||||
- [ ] `notifier.py` consumes both `orders.processed.q` and `orders.failed.q`.
|
- [x] `notifier.py` consumes both `orders.processed.q` and `orders.failed.q`.
|
||||||
- [ ] Print concise final messages, e.g.:
|
- [x] Print concise final messages, e.g.:
|
||||||
- [ ] `ORDER 1001 PROCESSED`
|
- [x] `ORDER 1001 PROCESSED`
|
||||||
- [ ] `ORDER 1003 FAILED AFTER RETRIES`
|
- [x] `ORDER 1003 FAILED AFTER RETRIES`
|
||||||
- [ ] ACK all notifier messages.
|
- [x] ACK all notifier messages.
|
||||||
|
|
||||||
Success check:
|
Success check:
|
||||||
|
|
||||||
- [ ] After running producer, notifier shows both success and failure events.
|
- [x] After running producer, notifier shows both success and failure events.
|
||||||
|
|
||||||
## Step 6: End-to-End Run (10 min)
|
## Step 6: End-to-End Run (10 min)
|
||||||
|
|
||||||
Run in 3 terminals:
|
Run in 3 terminals:
|
||||||
|
|
||||||
- [ ] Terminal A: `uv run worker.py`
|
- [x] Terminal A: `uv run worker.py`
|
||||||
- [ ] Terminal B: `uv run notifier.py`
|
- [x] Terminal B: `uv run notifier.py`
|
||||||
- [ ] Terminal C: `uv run producer.py`
|
- [x] Terminal C: `uv run producer.py`
|
||||||
|
|
||||||
Expected behavior:
|
Expected behavior:
|
||||||
|
|
||||||
- [ ] Normal orders finish in `orders.processed.q` path.
|
- [x] Normal orders finish in `orders.processed.q` path.
|
||||||
- [ ] Failing orders retry 2 times then go `orders.failed.q`.
|
- [x] Failing orders retry 2 times then go `orders.failed.q`.
|
||||||
|
|
||||||
## Step 7: Failure Drill (10 min)
|
## Step 7: Failure Drill (10 min)
|
||||||
|
|
||||||
|
|||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
from typing import TypedDict
|
||||||
|
|
||||||
|
import json
|
||||||
|
import pika
|
||||||
|
from pika.adapters.blocking_connection import BlockingChannel
|
||||||
|
from pika.spec import Basic
|
||||||
|
|
||||||
|
conn = pika.BlockingConnection(pika.ConnectionParameters("localhost"))
|
||||||
|
ch = conn.channel()
|
||||||
|
|
||||||
|
ch.basic_qos(prefetch_count=1)
|
||||||
|
|
||||||
|
# hover over on_messae_callback
|
||||||
|
# the docs specify signature
|
||||||
|
|
||||||
|
|
||||||
|
class OrderMessage(TypedDict):
|
||||||
|
order_id: int
|
||||||
|
user_id: str
|
||||||
|
amount: float
|
||||||
|
should_fail: bool
|
||||||
|
retry_count: int
|
||||||
|
|
||||||
|
|
||||||
|
def on_order_processed(channel: BlockingChannel, method: Basic.Deliver, properties, body):
|
||||||
|
order: OrderMessage = json.loads(body)
|
||||||
|
print(f"processed order: {order["order_id"]}")
|
||||||
|
channel.basic_ack(delivery_tag=method.delivery_tag)
|
||||||
|
|
||||||
|
|
||||||
|
def on_order_failed(channel: BlockingChannel, method: Basic.Deliver, properties, body):
|
||||||
|
order: OrderMessage = json.loads(body)
|
||||||
|
print(f"failed after retries: {order["order_id"]}")
|
||||||
|
channel.basic_ack(delivery_tag=method.delivery_tag)
|
||||||
|
|
||||||
|
|
||||||
|
ch.basic_consume(queue="orders.processed.q",
|
||||||
|
on_message_callback=on_order_processed, auto_ack=False)
|
||||||
|
ch.basic_consume(queue="orders.failed.q",
|
||||||
|
on_message_callback=on_order_failed, auto_ack=False)
|
||||||
|
|
||||||
|
# easy to forget
|
||||||
|
print("[notifier] waiting on messages")
|
||||||
|
ch.start_consuming()
|
||||||
|
|||||||
@@ -75,6 +75,6 @@ def on_message(
|
|||||||
|
|
||||||
|
|
||||||
ch.basic_consume(queue="orders.q",
|
ch.basic_consume(queue="orders.q",
|
||||||
on_message_callback=on_message, auto_ack=False)
|
on_message_callback=on_message, auto_ack=False) # the manual ack so this is false
|
||||||
print("[worker] waiting for messages...")
|
print("[worker] waiting for messages...")
|
||||||
ch.start_consuming()
|
ch.start_consuming()
|
||||||
|
|||||||
Reference in New Issue
Block a user