Reason About Dependency Loading with Topological Sort
RobinhoodSoftware Engineer · Technical ScreenLast updated
Tests graph construction, topological sorting (Kahn's algorithm or DFS), cycle detection, and deterministic tie-breaking for modular dependency resolution.
Module Dependency Resolver
Robinhood's trading platform relies on dozens of internal micro-services and libraries (such as market_data, order_routing, risk_engine, and auth). When starting up an environment, services must be initialized in an order such that every dependency of a service is fully loaded before the service itself starts.
You are given a list of service names services and a list of dependency pairs dependencies, where each pair [u, v] indicates that service v depends on service u (i.e., u must be loaded before v).
Write a function to return a valid sequence in which all services can be loaded.
Requirements
- If there are circular dependencies (a cycle), return an empty list
[]to indicate that the system cannot be safely loaded. - If multiple valid initialization orders exist, return the order that is lexicographically smallest at each step (tie-breaking).
- Any service mentioned in
servicesmust appear in the final output unless there is a cycle.
Function Signature
def resolve_load_order(services: list[str], dependencies: list[list[str]]) -> list[str]:
pass
Examples
Example 1:
services = ["auth", "risk_engine", "order_routing", "market_data"]
dependencies = [
["auth", "risk_engine"],
["auth", "order_routing"],
["market_data", "order_routing"],
["risk_engine", "order_routing"]
]
# Output: ["auth", "market_data", "risk_engine", "order_routing"]
Explanation: Both auth and market_data have no prerequisites. Because auth is lexicographically smaller than market_data, it is chosen first. Then market_data is selected. Next, risk_engine (depends only on auth) becomes available, followed by order_routing.
Example 2:
services = ["service_a", "service_b"]
dependencies = [
["service_a", "service_b"],
["service_b", "service_a"]
]
# Output: []
Explanation: service_a and service_b depend on each other, creating a circular dependency.
Constraints
1 <= len(services) <= 10000 <= len(dependencies) <= 5000- Each service name consists of lowercase English letters and underscores, with length between 1 and 30.
- All names in
dependenciesare guaranteed to exist inservices. - Dependencies may contain duplicate edges.
Hints
Hint 1
Represent the system as a directed graph where an edge u -> v means service u must run before service v.
Hint 2
Track the in-degree (number of unsatisfied prerequisites) for each service, and use a min-heap instead of a standard FIFO queue to satisfy the lexicographical tie-breaking requirement.
Hint 3
If the number of services processed in the final topological order is less than the total number of unique services, a cycle exists.
Follow-up questions
- How would you modify your algorithm to support parallel startup, returning groups of services that can be initialized concurrently in stages?
- If a cycle is detected, how would you identify and return the exact nodes involved in the cycle to help developers debug the dependency graph?
- How would the design change if dependency definitions were loaded dynamically over a network and the graph was too large to fit in memory on a single machine?
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.