Implement a Time-Aware Task Manager
AnthropicSoftware Engineer · Technical ScreenLast updated
Design an in-memory task manager supporting per-user task versioning, time-to-live (TTL) expiration, and point-in-time historical queries.
Problem Statement
Design and implement an in-memory time-aware task management system. The system maintains tasks on a per-user basis where each task version is associated with a creation timestamp and a time-to-live (ttl). A task is considered active at timestamp t if it was set at start_time and start_time <= t < start_time + ttl, provided it has not been overwritten or deleted before t.
All mutation calls (set_task and delete_task) arrive in non-decreasing order of timestamp across the entire system. Queries (get_task_at and get_active_tasks_at) may specify any arbitrary non-negative timestamp (past, present, or future relative to mutations seen so far).
Implement the TimeAwareTaskManager class:
__init__(): Initializes the data structures.set_task(user_id: str, task_id: str, payload: str, timestamp: int, ttl: int) -> None: Creates or updates a task foruser_id. The task becomes active attimestampand expires attimestamp + ttl. If a prior version of this task was still active attimestamp, its validity ends attimestamp.delete_task(user_id: str, task_id: str, timestamp: int) -> bool: Deletestask_idforuser_idstarting attimestamp. ReturnsTrueif the task was currently active attimestamp(and is now terminated), orFalseif the task was already expired, deleted, or never existed.get_task_at(user_id: str, task_id: str, timestamp: int) -> str | None: Returns the payload oftask_idforuser_idattimestamp. ReturnsNoneif the task was not active at that timestamp.get_active_tasks_at(user_id: str, timestamp: int) -> list[str]: Returns a list of all activetask_ids foruser_idattimestamp, sorted lexicographically.
Constraints
1 <= len(user_id), len(task_id), len(payload) <= 320 <= timestamp <= 10^91 <= ttl <= 10^6- Timestamps for mutation operations (
set_task,delete_task) are non-decreasing:timestamp_k <= timestamp_{k+1}. - At most
5 * 10^4total calls across all methods. - At most
200uniquetask_ids per user.
Example
tm = TimeAwareTaskManager()
# User 'alice' creates task 'T1' at t=10 with TTL=15 (valid in [10, 25))
tm.set_task("alice", "T1", "Payload A", 10, 15)
# User 'alice' updates task 'T1' at t=20 with TTL=10 (valid in [20, 30))
# Prior version now only valid in [10, 20)
tm.set_task("alice", "T1", "Payload B", 20, 10)
# User 'alice' creates task 'T2' at t=22 with TTL=5 (valid in [22, 27))
tm.set_task("alice", "T2", "Payload C", 22, 5)
assert tm.get_task_at("alice", "T1", 15) == "Payload A"
assert tm.get_task_at("alice", "T1", 20) == "Payload B"
assert tm.get_task_at("alice", "T1", 25) == "Payload B"
assert tm.get_task_at("alice", "T1", 30) is None # Expired at t=30
assert tm.get_active_tasks_at("alice", 24) == ["T1", "T2"]
assert tm.get_active_tasks_at("alice", 28) == ["T1"]
# Delete T1 at t=29 (returns True because T1 is active at t=29)
assert tm.delete_task("alice", "T1", 29) is True
assert tm.get_task_at("alice", "T1", 29) is None
assert tm.delete_task("alice", "T1", 35) is False # Already expired/deleted
Edge Cases
- Overwriting a task before its previous TTL has expired should curtail the prior version's end time to the new mutation's timestamp.
- Deleting an already expired task returns
Falseand does not extend or revive any state. timestampexactly at expiration timet = start_time + ttlmust be considered expired.
Hints
Hint 1
Since mutation timestamps arrive in non-decreasing order, each task's timeline can be stored as an ordered sequence of non-overlapping intervals `(start_time, end_time, payload)`.
Hint 2
For point-in-time retrieval of a single task (`get_task_at`), binary search over that task's version list allows `O(log V)` lookup time.
Hint 3
For `get_active_tasks_at`, leverage the per-user constraint (at most 200 tasks per user) by checking each task's state at the query timestamp via binary search.
Follow-up questions
- How would your design change if mutation timestamps could arrive out of order (e.g., due to network latency in a distributed environment)?
- If the number of unique tasks per user grew to hundreds of thousands, how would you optimize `get_active_tasks_at` to avoid scanning every task?
- How would you implement persistent background eviction to free memory for expired intervals in a long-running production service?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.