liveBook · Manning

Sendwork

As explained in Build and Orchestrator in Go (From Scratch)

SendWork is a manager method that selects a worker and sends it a task event through the worker API.

SendWork is the manager operation that turns a pending task event into a request to a worker. Its operational job is small but central: take queued work, choose where it should run, record the manager’s view of that decision, and submit the event through the worker API. section 7.3.2 section 7.5

A basic dispatch pass proceeds as follows:

  • Check whether the Pending queue contains task events; do nothing when it is empty. section 7.3.2
  • Select a worker, dequeue one TaskEvent, and retain its Task for state and tracking updates. section 7.3.2
  • Store the event and task-to-worker relationships in EventDb, WorkerTaskMap, and TaskWorkerMap, then mark the task Scheduled in TaskDb. section 7.3.2
  • JSON-encode the event and POST it to the selected worker’s /tasks endpoint. section 7.3.2
  • Handle connection and response errors; a connection failure returns the event to Pending, while an unsuccessful response is decoded and logged. section 7.3.2
Listing 7.5 The manager’s SendWork method
func (m *Manager) SendWork() {
    if m.Pending.Len() > 0 {
        w := m.SelectWorker()                                         #1
 
        e := m.Pending.Dequeue()
        te := e.(task.TaskEvent)                                      #2
        t := te.Task
        log.Printf("Pulled %v off pending queue\n", t)
 
        m.EventDb[te.ID] = &te                                        #3
        m.WorkerTaskMap[w] = append(m.WorkerTaskMap[w], te.Task.ID)   #4
        m.TaskWorkerMap[t.ID] = w                                     #5
 
        t.State = task.Scheduled
        m.TaskDb[t.ID] = &t
 
        data, err := json.Marshal(te)                                 #6
        if err != nil {
            log.Printf("Unable to marshal task object: %v.\n", t)
        }

The core implementation makes dispatch state explicit: dequeue the event, update manager maps, set Scheduled, and marshal the payload before the HTTP request. section 7.3.2

Dispatching three tasks to one worker

Create Task and TaskEvent values, add each event to the manager, and call SendWork after each addition. With one registered worker, every event is sent to that worker’s API. The worker accepts the request into its own queue; starting the task happens separately in the worker’s goroutine. section 7.5

A successful request means the manager has handed off work, not necessarily that the task has completed. The manager tracks its dispatch-side state, while the worker queues requests and performs start or stop operations asynchronously. Later task updates reconcile those distinct views. section 7.5

When scheduling becomes task-aware, SendWork changes order: dequeue and record the event first, then pass the task to SelectWorker. The scheduler filters candidate nodes, scores them, and picks one; the selected node’s Name replaces the earlier worker-address string in maps and URLs. section 10.5.2

How Build and Orchestrator in Go (From Scratch) covers it

How deep it goes
Works through queue handling, state maps, JSON, HTTP responses, and a later scheduler-driven reordering.
Examples
Uses three TaskEvent values sent from one manager to a single running worker.
What it assumes
Assumes manager queues, task events, and a worker API while making their dispatch interaction explicit.
What you can do after
Build it from scratch by dequeuing events, tracking assignments, posting JSON, and handling worker errors.
How it connects
Connects Pending queues, TaskEvent, SelectWorker, task state, worker APIs, and scheduler interfaces.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Build and Orchestrator in Go (From Scratch). The section links point to the parts of the book it draws on.