Inputs have the documented types. Message IDs, group IDs, and payloads are strings; empty strings are allowed. Payloads are immutable strings. All snapshots and returned lists must be fresh. Instances are independent. There is no clock, capacity limit, deletion, replay, or automatic delivery timeout.

Prototype: implement MessageQueue() with publish(message_id, payload) -> bool and consume() -> dict | None. Publish returns True once per ID across the queue's lifetime, including IDs already consumed; a duplicate returns False without replacing content. Consume destructively returns the oldest {"id": id, "payload": payload} or None when empty.

Final: implement MessageBroker(max_attempts=2):

  • max_attempts is an integer; values below 1 raise ValueError. It counts deliveries, including the initial delivery.
  • publish(message_id, payload) -> bool appends to a retained FIFO log. IDs remain unique for the broker's lifetime. Duplicate IDs return False and preserve the original payload.
  • subscribe(group_id) -> bool creates a group starting at the earliest retained message, including messages published before subscription. Return False if already subscribed; preserve existing progress.
  • poll(group_id) -> dict | None: unknown or caught-up groups return None. Otherwise return exactly {"id": id, "payload": payload, "attempt": n}. The first delivery at a position has attempt 1. An already in-flight delivery is returned again without incrementing its attempt. After a retryable rejection, poll redelivers the same message with the next attempt before any later message.
  • ack(group_id, message_id) -> bool: return True only for that group's current in-flight ID, clear it, and advance to the next log position. Unknown groups, wrong IDs, duplicate acknowledgments, and acknowledgments between rejection and redelivery return False without changing state.
  • nack(group_id, message_id) -> str | None: only a matching in-flight delivery is valid. Invalid calls return None unchanged. A valid call clears in-flight state. If its attempt is below the limit, return "retry" without advancing. At the limit, append {"id": id, "payload": payload, "attempts": n} to that group's dead letters, advance, reset attempts for the next message, and return "dead-letter".
  • dead_letters(group_id) -> list[dict]: return detached entries in failure order, or [] for an unknown group. Reading does not drain the list.

A rejected publish or invalid acknowledgment must not affect any group. Run python main.py --stage prototype, then python main.py --stage final (the default). Edit only exercise.py.

Drag or use the arrow keys to resize. Home collapses the question; End collapses the editor. Enter or double-click resets the split.
Loading editor…
No results yet.

Complete the starter code, then run the checks.
Results and errors will appear here.