Weighted Server Load Balancer with TTL
Reported by candidates from Stripe's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.
The Stripe OA reported in November 2023 looks like a load balancer story, but it really reduces to a simulation with two data structures: a min-heap of expiring tasks and a scan over servers for the lightest eligible one. Tasks arrive in time order, so you expire first, then assign. That's the whole shape. If you've got an invite and 48 hours, the trick is ordering the steps correctly and handling ties. StealthCoder sits invisibly as a safety net on the live OA if you blank on the heap bookkeeping, but the logic here is learnable tonight.
The problem
Assign tasks to available servers while tracking active weighted load. Each server row is name,maxLoad. Each task row is time,taskId,weight,ttl. Process tasks in input order; task times are nondecreasing. Before each task, expire every earlier assignment whose end time startTime + ttl is at most the current task's time, and remove its weight from that server. A server is eligible when its current load plus the task's weight does not exceed maxLoad. Choose the eligible server with the smallest current load, breaking ties by lexicographically smaller server name. An accepted task remains active until its end time. Return one result per task as taskId:serverName. Return taskId:NONE when no server can accept the task. Function assignWeightedTasks(servers: String[], tasks: String[]) → String[] Examples Example 1 servers = ["a,5","b,4"] tasks = ["0,t1,3,5","1,t2,2,3","4,t3,4,2","5,t4,5,1"] return = ["t1:a","t2:b","t3:b","t4:a"] The first task uses lexical tie-breaking. The second goes to the lighter server. Its TTL expires at time 4, making b available for t3; t1 expires before t4. Example 2 servers = ["solo,3"] tasks = ["0,t1,3,5","0,t2,1,2","5,t3,3,1"] return = ["t1:solo","t2:NONE","t3:solo"] The second task exceeds the remaining capacity. The first task expires at time 5, so the final task is accepted. Example 3 servers = ["zeta,10","alpha,10"] tasks = ["2,x,1,3","2,y,1,3"] return = ["x:alpha","y:zeta"] Both servers begin at load 0, so alpha wins the lexical tie. The next task then chooses the lighter zeta. Constraints 1 <= servers.length <= 1000; server names are unique. 1 <= tasks.length <= 10000; task IDs are unique and times are nondecreasing. Every maxLoad, task weight, and TTL is a positive integer at most 10^9. Times and computed end times fit in signed 64-bit integers. Rejected tasks do not consume load. Tasks at the same time are processed in input order, and expirations at that time happen before assignment.
Reported by candidates. Source: FastPrep
Pattern and pitfall
Keep a map of server name to current load, plus a min-heap keyed by end time holding (endTime, server, weight) for accepted tasks. Before each task, pop while the top's endTime is at most the current time, and subtract the weight from that server. Then scan all servers (at most 1000, with 10000 tasks, so about 10 million checks) and pick the eligible one with the smallest load, breaking ties by smaller name. If none fits, output taskId:NONE and push nothing onto the heap. Common pitfalls: using less-than instead of less-than-or-equal on expiry, pushing rejected tasks, and overflow on startTime + ttl (use 64-bit). Sorting server names once up front makes the tie-break free during the scan. If you freeze mid-assessment, StealthCoder can supply the heap-plus-scan skeleton from the live screen, but know the expire-then-assign order cold.
StealthCoder is the hedge for the one pattern you didn't drill. It runs invisibly during the screen share.
You can drill Weighted Server Load Balancer with TTL 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. If you're reading this with an OA window open, you're who this was built for.
Get StealthCoderRelated leaked OAs
You've seen the question.
Make sure you actually pass Stripe's OA.
Stripe reuses patterns across OAs. If you're reading this with an OA window open, you're who this was built for. Works on HackerRank, CodeSignal, CoderPad, and Karat.
Weighted Server Load Balancer with TTL FAQ
What's the trick in the Stripe weighted load balancer problem?+
Expire before you assign. Use a min-heap on end time to release load from finished tasks, then scan servers for the lowest-load one that still fits. Ties go to the lexicographically smaller name. Rejected tasks never touch the heap or any load.
Do I need a heap, or can I just loop over everything?+
A heap is cleaner and faster. Rescanning all active tasks per new task works at these sizes but wastes time and invites bugs. A heap keyed on startTime + ttl lets you pop exactly the expired ones and nothing else.
What's the time complexity I should aim for?+
Roughly O(T log T + T * S), where T is tasks and S is servers. With 10000 tasks and 1000 servers, the linear scan per task is fine. A balanced structure over servers is possible but unnecessary for these constraints.
Which edge cases break most solutions?+
Expiry at exactly the current time (end time equal to now must expire), tasks at the same timestamp, weights exceeding every maxLoad, and overflow on startTime + ttl. Example 2 covers the rejection case and the exact-expiry case, so trace it by hand.
How do I prepare for this in 48 hours?+
Write the solution once from scratch using a heap and a server load map, then run all three examples by hand. Focus on the order of operations and the tie-break comparator. Event-simulation problems with expirations show up often in OAs, so the pattern transfers.