Fan-out¶
FanOutStep builds one sub-graph per key of a dict and returns a dict of results with the
same keys. Each branch is cached like any other step.
over: the dict to iterate.factory(key, value): returns the branch'sStepResult.max_workers: run branches on a thread pool of this size. The default runs them one by one.
flowchart LR
over["over: dict with keys a, b, c"] --> fa["factory('a', value)"] --> ra["branch a"]
over --> fb["factory('b', value)"] --> rb["branch b"]
over --> fc["factory('c', value)"] --> rc["branch c"]
ra --> out["dict with keys a, b, c"]
rb --> out
rc --> out
"""FanOutStep: one sub-graph per key, run on a thread pool, results as a dict."""
from dataclasses import dataclass
from pydantic import BaseModel
from adag import FanOutStep, NullObserver, Pipeline, Step
class Size(BaseModel):
chars: int
@dataclass(frozen=True)
class Measure(Step[Size]):
text: str
def run(self, text: str) -> Size:
return Size(chars=len(text))
documents = {"intro": "Hello.", "body": "A longer paragraph.", "end": "Bye."}
sizes = FanOutStep(
over=documents,
factory=lambda key, text: Measure(text=text)(),
max_workers=3,
)()
result = Pipeline(sizes).execute(observer=NullObserver())
print({key: size.chars for key, size in result.items()})
A failing branch raises its own exception and stops the fan-out. With a dispatcher, the other
branches still finish, and the fan-out raises FanOutBranchError: its failed dict maps each
failed key to the error. To run branches in separate processes or on a scheduler, see
Dispatch.