Execute Dependency-Constrained Work at Scale
MetaSoftware Engineer · OnsiteLast updated
This problem tests the ability to design an execution engine that manages task dependencies using a directed acyclic graph (DAG), respects concurrency limits, and handles task failures.
Problem: Dependency-Aware Task Runner
You are tasked with building a task execution engine that processes a set of jobs based on their dependencies. Each job has a unique ID, a list of IDs it depends on (pre-requisites), and a function to execute. A job can only start once all its dependencies have completed successfully.
Requirements
- Dependency Resolution: A job must not start until all its dependencies have finished.
- Concurrency Limiting: You must support a
max_workersparameter to limit the number of jobs executing simultaneously. - Failure Propagation: If a job fails, all jobs that depend on it (directly or indirectly) must be cancelled or marked as failed, and the engine should stop scheduling them.
- Execution: Provide a method
execute_all(jobs)that returns a dictionary mapping job IDs to their execution status (SUCCESS, FAILED, or CANCELLED).
Interface
class Job:
def __init__(self, job_id, dependencies, task_func):
self.job_id = job_id
self.dependencies = dependencies # List of job_ids
self.task_func = task_func
def execute_all(jobs: List[Job], max_workers: int) -> Dict[str, str]:
# Returns map of {job_id: status}
pass
Constraints
jobscount: up to 10,000.max_workers: up to 100.- The graph is guaranteed to be a Directed Acyclic Graph (DAG).
Example
Input: Jobs A (no deps), B (deps: [A]), C (deps: [A]). If A succeeds, B and C can run concurrently. If A fails, B and C are cancelled.
Edge Cases
- Cycles in dependencies (the problem guarantees a DAG, but how would you detect/handle an invalid graph?).
- A job depending on a non-existent ID.
- Empty list of jobs.
Hints
Hint 1
Represent the graph as an adjacency list where each node keeps track of its 'in-degree' (number of pending dependencies).
Hint 2
Use a thread-safe queue to manage jobs that are ready to run (in-degree of 0) and a thread pool to manage the workers.
Hint 3
Use a thread-safe data structure to track the state of each job and implement a mechanism to propagate failure status to downstream dependencies.
Follow-up questions
- How would you modify this engine to support task retries with exponential backoff?
- If the tasks were distributed across multiple physical nodes instead of local threads, what components would you need to add to maintain consistency?
- How would you implement a priority queue mechanism to ensure high-priority jobs get executed before others when the worker pool is saturated?
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.