Named Async Task Scheduler
Reported by candidates from Airwallex's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.
The mistake that sinks a first attempt on this Airwallex task is treating ADVANCE as one big jump instead of a loop of completions. Airwallex candidates reported this Named Async Task Scheduler in October 2026, and it's a queue simulation dressed up as a scheduler. Per-name FIFO queues, a virtual clock, and strict event ordering. The logic isn't hard. The details are what bite you. If you blank on the tie-breaking or the stale-completion handling mid-assessment, StealthCoder is the invisible safety net that reads the problem and hands you a working structure.
The problem
Simulate an asynchronous task scheduler. Process operations in order while maintaining a virtual clock that starts at 0. Operations ["ADD", name, taskId, duration]: add a task with a positive integer duration. If no task with that name is running, start it now; otherwise append it to that name's FIFO queue. ["ADVANCE", delta]: advance the clock by a nonnegative integer delta and process every task completion at or before the target time. ["CANCEL", name]: cancel the currently running task with that name. If one exists, immediately start the next queued task of the same name. It does not remove the remaining queue. ["CLEAR", name]: remove the running task and every queued task with that name. It never affects another name. Tasks with the same name never overlap. Tasks with different names may run concurrently. Completion ordering A queued task starts at the exact time its predecessor finishes or is cancelled. During ADVANCE, process completions by smaller finish time, then by lexicographically smaller task name. For each selected completion, record its FINISH event and start that name's next task before processing the next completion. Durations are positive, so a newly started task cannot finish at the same instant. After processing completions, set the clock to the target time. A task finishing exactly at the target completes before the next input operation. Do not automatically drain unfinished work after the final operation. Return value Return every lifecycle event in order using these exact forms: time:START:name:taskId time:QUEUE:name:taskId time:FINISH:name:taskId time:CANCEL:name:taskId, or time:CANCEL_NONE:name time:CLEAR:name:taskId for the running task first and then queued tasks in FIFO order, or time:CLEAR_NONE:name Function runNamedTaskScheduler(operations: String[][]) → String[] Examples Example 1 operations = [["ADD","alpha","a1","5"],["ADD","alpha","a2","2"],["ADD","beta","b1","3"],["ADVANCE","3"],["ADVANCE","2"],["ADVANCE","2"]] return = ["0:START:alpha:a1","0:QUEUE:alpha:a2","0:START:beta:b1","3:FINISH:beta:b1","5:FINISH:alpha:a1","5:START:alpha:a2","7:FINISH:alpha:a2"] The two names run concurrently. The second alpha task waits for a1, while beta finishes independently at time 3. Example 2 operations = [["ADD","sync","s1","10"],["ADD","sync","s2","4"],["ADD","sync","s3","1"],["ADVANCE","3"],["CANCEL","sync"],["ADVANCE","4"],["ADVANCE","1"]] return = ["0:START:sync:s1","0:QUEUE:sync:s2","0:QUEUE:sync:s3","3:CANCEL:sync:s1","3:START:sync:s2","7:FINISH:sync:s2","7:START:sync:s3","8:FINISH:sync:s3"] Cancelling s1 at time 3 immediately advances the same-name queue. Its stale time-10 completion never appears. Example 3 operations = [["ADD","red","r1","8"],["ADD","red","r2","2"],["ADD","blue","b1","4"],["ADVANCE","2"],["CLEAR","red"],["ADVANCE","2"],["CANCEL","red"],["CLEAR","red"]] return = ["0:START:red:r1","0:QUEUE:red:r2","0:START:blue:b1","2:CLEAR:red:r1","2:CLEAR:red:r2","4:FINISH:blue:b1","4:CANCEL_NONE:red","4:CLEAR_NONE:red"] Clearing red removes its running task first and then its queued task, without affecting the concurrent blue task. Constraints 0 <= operations.length <= 100000. Every row has one of the four exact forms above. name and taskId contain 1 to 20 lowercase ASCII letters, digits, or underscores, and do not contain colons. Every taskId in an ADD operation is globally unique. 1 <= duration <= 10^9 and 0 <= delta <= 10^9. The virtual clock never exceeds 10^14. The returned array contains at most 200000 events.
Reported by candidates. Source: FastPrep
Pattern and pitfall
Keep a map from name to a deque plus the currently running task with its finish time. Put each running task's finish time and name into a min-heap. On ADVANCE, compute target = clock + delta, then pop while the heap top finishes at or before target. Order by finish time, then name. Emit FINISH, start the next queued task at that finish time, and push it. The classic pitfall is stale heap entries. CANCEL and CLEAR remove a running task, but its old heap entry stays. Fix it by storing taskId in the entry and checking it matches the name's current running task before processing (lazy deletion). Also remember CANCEL starts the next task at the current clock, CLEAR emits the running task first, then queued ones in FIFO order, and nothing drains after the last operation. StealthCoder is your hedge if the lazy deletion detail slips under pressure.
If you see this problem in your OA tomorrow, the play is to recognize the pattern in 30 seconds. StealthCoder buys you that recognition.
You can drill Named Async Task Scheduler cold, or you can hedge it. StealthCoder runs invisibly during screen share and surfaces a working solution in under 2 seconds. The proctor sees the IDE. They don't see what's behind it. Built by an Amazon engineer who passed his OA cold and still thinks the filter is broken.
Get StealthCoderRelated leaked OAs
You've seen the question.
Make sure you actually pass Airwallex's OA.
Airwallex reuses patterns across OAs. Built by an Amazon engineer who passed his OA cold and still thinks the filter is broken. Works on HackerRank, CodeSignal, CoderPad, and Karat.
Named Async Task Scheduler FAQ
What's the core trick in the Named Async Task Scheduler?+
A per-name FIFO queue plus a global min-heap of running tasks keyed by finish time, then name. ADVANCE loops through heap pops up to the target time, starting each name's next task as its predecessor ends. Lazy deletion handles cancelled or cleared tasks.
How do I handle stale completions after CANCEL or CLEAR?+
Don't dig through the heap. Leave the old entry in place and, when you pop it, check that its taskId still matches the running task for that name. If not, skip it silently. That keeps every operation at O(log n).
How hard is this really?+
Medium. No fancy algorithm, but lots of small rules: tie-breaking by name, exact event string formats, and cancel versus clear semantics. Most failures come from output ordering and missed edge cases, not from the data structure choice.
What edge cases should I test before submitting?+
CANCEL and CLEAR on a name with nothing running, ADVANCE with delta 0, a task finishing exactly at the target time, two names finishing at the same instant, and CLEAR on a name with queued tasks. All three examples cover pieces of these.
How do I prepare in 48 hours?+
Write the scheduler once from scratch with a heap and deques, then run the three given examples by hand. Practice the lazy-deletion pattern and the event string formatting. Clock values reach 10^14, so use 64-bit integers.