Skip to main content
An OuterProduct Run forms a computation graph. The top-level client.run() creates a new Run and its root Call. Inside that Call, the scoped client can create child Calls within the same Run. This hierarchy allows OuterProduct to track each Call independently. For example, in the following code, the pipeline call orchestrates a 2-step workflow (first, prepare_data , then train_model ). Every function receives an OuterProduct client as its first argument. A function can ignore it, as _client does in the example below, or use it to create more Calls. Breaking an application into Calls gives OuterProduct durable boundaries where work can be retried, tracked, and checkpointed.

Retrying a Call

Use RetryStrategy to specify the maximum number of Attempts for a Call:
max_attempts includes the first Attempt. In this example, OuterProduct can try the Call up to three times. If no retry strategy is provided, the Call receives three Attempt by default. Pass RetryStrategy(max_attempts=1) to disable retries. Each Call defines its own retry strategy; a parent and its children can therefore use different limits.

Durable execution

OuterProduct checkpoints work at Call boundaries. Once a Call succeeds, its result is stored as part of the Run. If a parent Call fails and is retried, it begins executing again. When it reaches a child Call that already succeeded, OuterProduct returns the stored result instead of executing that child again. A long workflow can therefore recover from a failure without repeating all of its successful work. For example:
If a Call fails halfway through its function, its next Attempt starts that function again from the beginning. Split expensive or important stages into separate Calls when you want them checkpointed independently.