Add bounded concurrent pipeline execution

This commit is contained in:
2026-07-17 08:37:52 +00:00
parent 4023c66508
commit adfd3bd052
10 changed files with 958 additions and 41 deletions

View File

@@ -50,9 +50,13 @@ type RunInput struct {
Checkpoints CheckpointRecorder
Checkpoint CheckpointLoader
Debug DebugRecorder
// ExtractWorkers bounds run-wide extract jobs. Values less than one use a
// single worker so direct framework callers retain deterministic behavior.
ExtractWorkers int
pipeline ResolvedPipeline
llmClient contracts.StructuredLLMClient
pipeline ResolvedPipeline
llmClient contracts.StructuredLLMClient
extractDecision *CheckpointDecision
}
type RunOutput struct {
@@ -87,6 +91,9 @@ func (r *Runner) Run(ctx context.Context, input RunInput) (output RunOutput, err
if debugRecorder == nil {
debugRecorder = NoopDebugRecorder()
}
checkpoints = synchronizedCheckpointRecorder(checkpoints)
checkpointLoader = synchronizedCheckpointLoader(checkpointLoader)
debugRecorder = synchronizedDebugRecorder(debugRecorder)
input.Debug = debugRecorder
input.llmClient = wrapDebugLLMClient(input.llmClient, debugRecorder)
defer func() {
@@ -311,10 +318,10 @@ func (r *Runner) Run(ctx context.Context, input RunInput) (output RunOutput, err
}
if chunksAccepted {
for _, lane := range input.Prepared.lanes {
if err := r.runLane(ctx, input, checkpoints, checkpointLoader, doc, sourceInput, sessionID, canonicalChunks, lane, &output); err != nil {
return failOutput(output), err
}
laneOutput, laneErr := r.runLanes(ctx, input, checkpoints, checkpointLoader, doc, sourceInput, sessionID, canonicalChunks)
mergeLaneOutput(&output, laneOutput)
if laneErr != nil {
return failOutput(output), laneErr
}
}
@@ -376,10 +383,6 @@ func (r *Runner) Run(ctx context.Context, input RunInput) (output RunOutput, err
return output, nil
}
func (r *Runner) runLane(ctx context.Context, input RunInput, checkpoints CheckpointRecorder, checkpointLoader CheckpointLoader, doc *source.SourceDocument, sourceInput contracts.LLMInputMaterial, sessionID string, chunks []source.Chunk, prepared preparedLaneExecutor, output *RunOutput) error {
return r.runTypedLane(ctx, input, checkpoints, checkpointLoader, doc, sourceInput, sessionID, chunks, prepared, output)
}
func runWithRetry(ctx context.Context, retries int, run func(attempt int) (bool, *contracts.RejectedOutput, error)) (bool, *contracts.RejectedOutput, error) {
attempts := retries + 1
var last *contracts.RejectedOutput
@@ -389,12 +392,12 @@ func runWithRetry(ctx context.Context, retries int, run func(attempt int) (bool,
}
accepted, rejection, err := run(attempt)
if err != nil {
if ctxErr := ctx.Err(); ctxErr != nil {
return false, nil, ctxErr
}
if attempt == attempts {
return false, nil, fmt.Errorf("failed after %d attempt(s): %w", attempt, err)
}
if ctxErr := ctx.Err(); ctxErr != nil {
return false, nil, ctxErr
}
continue
}
if accepted {