Implement stateful connection router simulator
Company: Stripe
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: easy
Interview Round: Take-home Project
Quick Answer: This question evaluates design and implementation skills for a stateful connection router, focusing on round-robin load distribution, connection lifecycle handling (duplicate connects, disconnects, shutdowns), and per-target capacity and mapping management.
Constraints
- 1 <= num_targets
- 1 <= max_per_target
- connId values are unique per logical client connection (strings or integers)
- operations are processed sequentially in a single thread
- a shutdown target never comes back up
- shutdown(targetIndex) is only called with a valid index in [0, num_targets-1]
Examples
Input: (3, 5, [['connect', 'a'], ['connect', 'b'], ['connect', 'c'], ['connect', 'd']])
Expected Output: [0, 1, 2, 0]
Explanation: Round-robin over 3 targets with ample capacity: a->0, b->1, c->2, then pointer wraps so d->0.
Input: (3, 5, [['connect', 'a'], ['connect', 'a'], ['connect', 'b']])
Expected Output: [0, 0, 1]
Explanation: Part 2: the duplicate connect('a') returns the existing target 0 and does NOT advance the pointer, so b still lands on 1.
Input: (2, 5, [['connect', 'a'], ['connect', 'b'], ['disconnect', 'a'], ['disconnect', 'a'], ['disconnect', 'zzz']])
Expected Output: [0, 1, true, false, false]
Explanation: Part 3: first disconnect('a') succeeds (true); the second is now unknown (false); disconnect of a never-seen id is also false.
Input: (2, 1, [['connect', 'a'], ['connect', 'b'], ['connect', 'c']])
Expected Output: [0, 1, -1]
Explanation: Part 4: capacity 1 per target fills both targets with a and b; c finds every non-shutdown target full and returns -1 without changing state.
Input: (2, 1, [['connect', 'a'], ['connect', 'b'], ['disconnect', 'a'], ['connect', 'c']])
Expected Output: [0, 1, true, 0]
Explanation: Freeing target 0 via disconnect('a') lets the later connect('c') reuse the now-open slot on target 0.
Input: (3, 2, [['connect', 'a'], ['connect', 'b'], ['connect', 'c'], ['connect', 'd'], ['shutdown', 0], ['connect', 'e']])
Expected Output: [0, 1, 2, 0, ['a', 'd'], 1]
Explanation: Part 5: a->0, b->1, c->2, d wraps to 0 (now holds a,d). shutdown(0) evicts in creation order ['a','d']. Pointer is at 1, target 0 is offline, so e->1.
Input: (2, 5, [['shutdown', 0], ['shutdown', 0], ['connect', 'a'], ['connect', 'b']])
Expected Output: [[], [], 1, 1]
Explanation: Shutting down an empty target evicts nothing; repeating it is a no-op returning []. Target 0 is offline so both a and b route to target 1.
Input: (1, 1, [['connect', 'x'], ['shutdown', 0], ['connect', 'y'], ['disconnect', 'x']])
Expected Output: [0, ['x'], -1, False]
Explanation: Edge case, single target: x->0, shutdown(0) evicts ['x'], now no target is available so y->-1, and disconnect('x') returns false because x was already evicted.
Input: (3, 10, [['connect', 1], ['connect', 2], ['connect', 1], ['disconnect', 2], ['disconnect', 2]])
Expected Output: [0, 1, 0, true, false]
Explanation: Integer connIds: 1->0, 2->1, duplicate connect(1)->0 (no pointer change), disconnect(2) true, repeat disconnect(2) false.
Hints
- Keep four pieces of state: a conn_id -> target_index map, a per-target live count, a per-target boolean 'is shut down', and a single round-robin pointer.
- For eviction order on shutdown, store each target's members in insertion order (an ordered map / linked hash structure), so you can return evicted ids in connect-time order in O(k).
- Make connect idempotent FIRST: if conn_id is already mapped, return immediately and touch nothing (pointer, counts, membership all unchanged).
- The round-robin scan must skip BOTH shutdown targets and full targets; only advance the pointer when you actually assign, and only to one-past the chosen target.