Practice/Stripe/Worker Task Assignment
CodingMust
You are building a task assignment system for a support platform. The system needs to distribute incoming tasks to available workers based on various criteria that evolve across multiple parts of the problem.
The problem is divided into four progressive parts, each introducing additional complexity:
Implement a function assign_tasks(workers, tasks) that assigns each task to the worker with the least current workload.
Rules:
workers = ["alice", "bob", "charlie"] tasks = [ {"id": "task1", "duration": 5}, {"id": "task2", "duration": 3}, {"id": "task3", "duration": 7}, {"id": "task4", "duration": 2}, {"id": "task5", "duration": 4}, ]
Output:
[ {"taskId": "task1", "worker": "alice"}, # all at 0, alice first in list {"taskId": "task2", "worker": "bob"}, # bob and charlie at 0, bob first {"taskId": "task3", "worker": "charlie"}, # charlie at 0 (lowest) {"taskId": "task4", "worker": "bob"}, # bob at 3 (lowest) {"taskId": "task5", "worker": "alice"}, # alice and bob tied at 5, alice first ]
Walkthrough:
Extend the system to handle workers with specialties. Each worker now has a specialty field, and each task has a list of requiredSpecialties. A task can only be assigned to a worker whose specialty matches one of the task's required specialties.
Among eligible workers (those with a matching specialty), assign to the one with the least workload (using the same tiebreaker rules as Part 1).
` workers = [ {"name": "alice", "specialty": "billing"}, {"name": "bob", "specialty": "technical"}, {"name": "charlie", "specialty": "billing"}, {"name": "diana", "specialty": "technical"}, ]
tasks = [ {"id": "task1", "duration": 5, "requiredSpecialties": ["billing"]}, {"id": "task2", "duration": 3, "requiredSpecialties": ["technical"]}, {"id": "task3", "duration": 7, "requiredSpecialties": ["billing", "technical"]}, {"id": "task4", "duration": 2, "requiredSpecialties": ["billing"]}, {"id": "task5", "duration": 4, "requiredSpecialties": ["technical"]}, ] `
Output:
[ {"taskId": "task1", "worker": "alice"}, # billing: alice(0), charlie(0) -> alice first {"taskId": "task2", "worker": "bob"}, # technical: bob(0), diana(0) -> bob first {"taskId": "task3", "worker": "charlie"}, # all eligible: charlie(0) and diana(0) lowest, charlie first {"taskId": "task4", "worker": "alice"}, # billing: alice(5), charlie(7) -> alice lower {"taskId": "task5", "worker": "diana"}, # technical: bob(3), diana(0) -> diana lower ]
requiredSpecialties listAdd account affinity to the assignment logic. Each task now has an accountId field. If a worker has previously handled a task from the same account, that worker should be prioritized for new tasks from that account.
Priority order:
` workers = [ {"name": "alice", "specialty": "billing"}, {"name": "bob", "specialty": "billing"}, {"name": "charlie", "specialty": "billing"}, ]
tasks = [ {"id": "task1", "duration": 5, "requiredSpecialties": ["billing"], "accountId": "acme"}, {"id": "task2", "duration": 3, "requiredSpecialties": ["billing"], "accountId": "globex"}, {"id": "task3", "duration": 7, "requiredSpecialties": ["billing"], "accountId": "acme"}, {"id": "task4", "duration": 2, "requiredSpecialties": ["billing"], "accountId": "acme"}, {"id": "task5", "duration": 4, "requiredSpecialties": ["billing"], "accountId": "globex"}, ] `
Output:
[ {"taskId": "task1", "worker": "alice"}, # no affinity yet; all at 0, alice first {"taskId": "task2", "worker": "bob"}, # no affinity; bob and charlie at 0, bob first {"taskId": "task3", "worker": "alice"}, # alice has acme affinity -> prioritized {"taskId": "task4", "worker": "alice"}, # alice still has acme affinity {"taskId": "task5", "worker": "bob"}, # bob has globex affinity ]
Walkthrough:
Extend the system to handle workers going offline. Workers can become unavailable at any point, and the system must adapt.
New input: An additional parameter offline_events specifies when workers go offline:
offline_events = [ {"worker": "alice", "afterTaskIndex": 2} # alice goes offline after task index 2 ]
When a worker goes offline:
` workers = [ {"name": "alice", "specialty": "billing"}, {"name": "bob", "specialty": "billing"}, {"name": "charlie", "specialty": "billing"}, ]
tasks = [ {"id": "task1", "duration": 5, "requiredSpecialties": ["billing"], "accountId": "acme"}, {"id": "task2", "duration": 3, "requiredSpecialties": ["billing"], "accountId": "globex"}, {"id": "task3", "duration": 7, "requiredSpecialties": ["billing"], "accountId": "acme"}, {"id": "task4", "duration": 2, "requiredSpecialties": ["billing"], "accountId": "acme"}, {"id": "task5", "duration": 4, "requiredSpecialties": ["billing"], "accountId": "globex"}, ]
offline_events = [ {"worker": "alice", "afterTaskIndex": 2} ] `
Output:
[ {"taskId": "task1", "worker": "alice"}, # alice gets acme (task index 0) {"taskId": "task2", "worker": "bob"}, # bob gets globex (task index 1) {"taskId": "task3", "worker": "alice"}, # alice has acme affinity (task index 2) # alice goes offline after task index 2 {"taskId": "task4", "worker": "charlie"}, # alice offline; charlie lowest workload (0) {"taskId": "task5", "worker": "bob"}, # bob has globex affinity ]