Skip to content

Using coroutines to execute multiple steps and subworkflows in a single worker #1218

@BoPeng

Description

@BoPeng

#1056

Right now our worker is executed like this:

  1. worker executes a step or nested workflow,
  2. worker sends pending requests to controller, waiting for a response
  3. controller sends the requests to an idle worker or start a new worker to work on the request
  4. controller sends the result back to the worker
  5. worker continues to run

The problem here is that there is potentially a large number of workers waiting for their requests to be satisfied.

This ticket proposes the use of Python coroutines/generator to resolve this problem. The technique is demonstrated in the following example:

def step():
    requested = yield 'request 1'
    return 'step completed'

def run_step():
    try:
        runner = step()
        pending = next(runner)
        while True:
            # sends result back to the generator AND fetch the next one
            runner.send('resolved')
    except StopIteration as e:
        # returned value is the value of StopIterator
        return e.value

That is to say,

  1. step executor becomes a generator function
  2. Instead of sending requests directly to controller, the step executor yield the request to the runner.
  3. the runner receives the request and send to the controller.
  4. the runner can at the same time request more work for the worker and starts running
  5. the runner receives result from the controller and stores it (a stack)
  6. Once the additional work has been completed (stack popped), the returned result will be send back to the generator function so that the original step can continue

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions