Repository navigation
Expand file tree
/
Copy pathfifo_ordering.py
More file actions
54 lines (41 loc) 路 1.65 KB
/
Copy pathfifo_ordering.py
File metadata and controls
54 lines (41 loc) 路 1.65 KB
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
"""FIFO: per-entity ordering with a FIFO topic fanning out to a FIFO queue.
Messages with the same group id (here: the account) are processed strictly in order, one at a
time; different groups are processed concurrently. Publishing the same message id twice within
five minutes is deduplicated by SNS/SQS.
Run: uv run python examples/fifo_ordering.py
"""
from __future__ import annotations
import asyncio
import dataclasses
import fanferro
from examples._common import make_client, unique
@fanferro.message_type("bank.transaction.v1")
@dataclasses.dataclass
class Transaction:
account: str
sequence: int
amount: int
async def main() -> dict[str, list[int]]:
client = make_client()
ledger = client.topic(
f"{unique('ledger')}.fifo",
group_id=lambda message: message.body.account, # group id derived from each message
)
projections = client.queue(f"{unique('balances')}.fifo")
client.subscription(ledger, projections)
order: dict[str, list[int]] = {}
consumer = client.consumer(projections, concurrency=8, wait_time=1)
@consumer.route(Transaction)
async def apply(tx: Transaction) -> None:
await asyncio.sleep(0.01)
order.setdefault(tx.account, []).append(tx.sequence)
async with client:
for sequence in range(5):
for account in ("alice", "bob"):
await ledger.publish(Transaction(account, sequence, 10), id=f"{account}-{sequence}")
await ledger.publish(Transaction("alice", 0, 10), id="alice-0") # duplicate: dropped
await consumer.run_until_idle(timeout=60)
print(order)
return order
if __name__ == "__main__":
asyncio.run(main())