Assignment
Implement a fake ticket system with delayed responses, duplicate webhook events, out-of-order versions, and a write that commits before timing out.
Build sequence
- Define read and update contracts with actor, record version, and operation ID.
- Handle duplicate and stale events without regressing local state.
- Bound retries and respect a simulated rate-limit response.
- Reconcile the ambiguous write outcome before retrying.
Acceptance checks
- Event replay does not duplicate effects.
- Local state never moves backward to an older version.
- The operator can distinguish a denied request from an unavailable service.
Evidence to keep
Submit the working artifact or decision document described above, the inputs used, and the observed results for every acceptance check. Include one failed attempt and the change you made after investigating it. Label fixture-based outcomes separately from live-system measurements. These artifacts become part of your final portfolio review.
Guided workshop: handle duplicate and out-of-order events
Third-party integrations fail independently. A webhook may be delivered twice or out of order. Persist event identity and source version, then apply only a valid transition. Authentication and signature verification must happen before trusting the payload; this exercise starts after that boundary.
# academy-check
versions = {}
seen = {}
def receive(event):
prior = seen.get(event["event_id"])
if prior is not None:
if prior != event:
raise ValueError("event ID reused with different payload")
return "duplicate"
key = (event["tenant"], event["ticket_id"])
if event["version"] <= versions.get(key, 0):
return "stale"
versions[key] = event["version"]
seen[event["event_id"]] = dict(event)
return "applied"
event = {"event_id": "e2", "tenant": "a", "ticket_id": "t1", "version": 2}
assert receive(event) == "applied"
assert receive(event) == "duplicate"
assert receive({**event, "event_id": "e1", "version": 1}) == "stale"
The in-memory dictionaries make the policy visible. A real receiver needs durable storage and a transaction combining deduplication with its mutation or outbox write. Otherwise a crash can acknowledge an event without preserving the intended work.
REST and GraphQL exercise: define the minimum ticket fields your application needs. For REST, document pagination, status handling, and update preconditions. For GraphQL, document selected fields, pagination cursors, and partial-error handling. A 200 HTTP response does not automatically mean every GraphQL field succeeded.
OAuth boundary: use a scoped authorization flow appropriate to the integration, store credentials on the server, and handle expiry and revocation. Test an expired token separately from rate limiting and a network timeout. Never retry a forbidden action until it happens to succeed.
Delivery exercise: enqueue verified events, return acknowledgement according to the provider contract, and process them with bounded retries. Simulate timeout after a remote write and reconcile using an idempotency key or remote state. Use synthetic CRM and support records before connecting real accounts.
Assessment: show duplicate, stale, reordered, unauthorized, rate-limited, and partially failed cases. Document who owns the adapter, how schema changes are detected, and how failed events are replayed. Protocol compatibility alone is not an integration plan.