Problem · Hash Table

WebSocket Load Balancer — Basic Load Balancing (Part 1)

Learn this problem
HardStripe logoStripeINTERNNEW GRADOA
See Stripe hiring insights

Problem statement

Stripe's notebook platform is based on Jupyter, which does not perform well with a large number of users. To provide a good developer experience, Stripe runs multiple Jupyter servers and directs developers to different servers according to current load.

Each incoming request represents a WebSocket connection. Once it reaches a target Jupyter server, the connection remains alive indefinitely and continuously contributes load. This exercise does not route requests over the network; routeRequests only determines the target for each incoming request.

Implement routeRequests, the Java-style execution adapter for the source function route_requests. The targets are numbered from 1 through numTargets.

Part 1: Basic load balancing (test cases 1–4)

For this exercise, assume every target starts with zero active connections. Process the requests in the order received. For every request:

  1. Choose a target with the smallest current number of active connections.
  2. If several targets have the same load, choose the one with the smaller target index.
  3. Assign the connection to that target. Because connections do not end in Part 1, its active-connection count increases by one and never decreases.

Routing in Part 1 is independent of the user's other requests. The objectId field also does not affect this basic load-balancing decision.

Request records

For this exercise, assume every request is a valid Part 1 record with the following comma-separated form:

CONNECT,connectionId,userId,objectId

For this exercise, assume every field is non-empty and does not contain a comma. The full source also lists an action,targetIndex schema for later parts, but those actions are not part of this Part 1 practice because their rules are not visible.

The parameter maxConnectionsPerTarget is retained because it appears in the source interface. The source explicitly marks it as used in Part 4, so it does not limit assignments in Part 1.

Return one log string for every CONNECT request, in input order, using the format:

connectionId,userId,targetIndex

The returned targetIndex is one-based.

Function

routeRequests(numTargets: int, maxConnectionsPerTarget: int, requests: String[]) → String[]

Examples

Example 1

numTargets = 3maxConnectionsPerTarget = 10requests = ["CONNECT,c1,u1,o1","CONNECT,c2,u2,o2","CONNECT,c3,u3,o3","CONNECT,c4,u4,o4","CONNECT,c5,u5,o5"]return = ["c1,u1,1","c2,u2,2","c3,u3,3","c4,u4,1","c5,u5,2"]

The first three connections take targets 1, 2, and 3 by the smaller-index tie-break. After all targets have load 1, the next tie again starts at target 1, followed by target 2.

Example 2

numTargets = 2maxConnectionsPerTarget = 1requests = ["CONNECT,a,sameUser,sameObject","CONNECT,b,sameUser,sameObject","CONNECT,c,sameUser,otherObject","CONNECT,d,otherUser,sameObject"]return = ["a,sameUser,1","b,sameUser,2","c,sameUser,1","d,otherUser,2"]

Part 1 uses only current target load, so repeated users and objects do not change the assignments. The value maxConnectionsPerTarget = 1 is not enforced in Part 1 because the source reserves that parameter for Part 4.

Constraints

  • For this exercise, assume 1 <= numTargets <= 10^5.
  • For this exercise, assume every target starts with zero active connections.
  • For this exercise, assume 1 <= maxConnectionsPerTarget <= 10^9; this value is retained but not used in Part 1.
  • For this exercise, assume 1 <= requests.length <= 2 * 10^5.
  • Every request is a valid CONNECT,connectionId,userId,objectId record whose fields are non-empty and contain no commas.
  • Target indices in the returned logs are one-based.

More Stripe problems

drafts saved locally
public String[] routeRequests(int numTargets, int maxConnectionsPerTarget, String[] requests) {
  // Write your code here.
}
numTargets3
maxConnectionsPerTarget10
requests["CONNECT,c1,u1,o1","CONNECT,c2,u2,o2","CONNECT,c3,u3,o3","CONNECT,c4,u4,o4","CONNECT,c5,u5,o5"]
expected["c1", "u1", "1", "c2", "u2", "2", "c3", "u3", "3", "c4", "u4", "1", "c5", "u5", "2"]
checking account