Skip to content

feat: parallelize forecast usage-artifact downloads to fix 45-min timeout - #48718

Merged
pelikhan merged 3 commits into
mainfrom
copilot/aw-fix-gh-aw-forecast-timeout
Jul 28, 2026
Merged

feat: parallelize forecast usage-artifact downloads to fix 45-min timeout#48718
pelikhan merged 3 commits into
mainfrom
copilot/aw-fix-gh-aw-forecast-timeout

Conversation

Copilot AI commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

gh aw forecast --days 30 was downloading usage artifacts for each completed workflow run serially; as run volume in github/gh-aw grew, the download phase alone exceeded the 45-minute job timeout with zero output produced.

Changes

  • Parallel artifact download (forecast_compute.go): replaces the serial per-run forecastLoadCachedRunAIC call inside forecastWorkflow with a new parallelLoadRunAICs helper that fans out downloads across a semaphore-bounded goroutine pool (default: 8 concurrent downloads), then processes results in original run order.

    // Before: serial, one download per loop iteration
    for _, r := range completed {
        runAIC := forecastLoadCachedRunAIC(ctx, r.DatabaseID, config.Verbose)
        ...
    }
    
    // After: all downloads in parallel, then process in order
    aicMap := parallelLoadRunAICs(ctx, completed, config)
    for _, r := range completed {
        runAIC := aicMap[r.DatabaseID]
        ...
    }
  • --concurrency flag (forecast_command.go): exposes DownloadConcurrency in ForecastConfig and as a CLI flag (default 0 = use the code default of 8; pass 1 for serial behaviour). The constant defaultForecastDownloadConcurrency = 8 lives in forecast_compute.go.

  • Context cancellation: parallelLoadRunAICs respects context cancellation at the semaphore-acquire step, so the existing --timeout flag cleanly interrupts in-flight downloads.

  • Tests: covers correct result collection with concurrency, graceful early exit on cancelled context, empty-input edge case, and flag registration.

…default)

Fixes the serial artifact-download bottleneck in `gh aw forecast --days 30`
that caused the Daily Spending Forecast workflow to time out after 45 minutes.

Changes:
- Add `parallelLoadRunAICs` to forecast_compute.go: fetches AIC values for all
  completed runs concurrently using a semaphore (default: 8 goroutines).
- Update `forecastWorkflow` to call `parallelLoadRunAICs` instead of the
  previous serial `forecastLoadCachedRunAIC` loop.
- Add `DownloadConcurrency int` field to `ForecastConfig` and expose it via a
  new `--concurrency` CLI flag (0 = use default of 8).
- Add tests: parallel returns all values, respects cancellation, handles empty
  input, and verifies the new CLI flag is registered."

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix timeout issue with daily spending forecast artifact download feat: parallelize forecast usage-artifact downloads to fix 45-min timeout Jul 28, 2026
Copilot AI requested a review from pelikhan July 28, 2026 19:59
@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot run forecast in pre agent steps to predownload data

Add a "Prefetch forecast usage artifacts" pre-agent step that runs
gh aw forecast with --concurrency 8 and --timeout 25 (discarding output)
before the main forecast step. Because forecastDownloadUsageArtifact skips
re-downloading artifacts already on disk, the main forecast step reads from
the local cache and completes in seconds.

Also adds --concurrency 8 to the main forecast step and reduces its --timeout
from 30 to 10 minutes since data is warm from the prefetch.

Recompiled daily-spending-forecast.lock.yml.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author

@copilot run forecast in pre agent steps to predownload data

Done. Added a "Prefetch forecast usage artifacts" step before "Run spending forecast" in daily-spending-forecast.md (commit 5c7c432).

The prefetch step runs gh aw forecast --concurrency 8 --timeout 25 and discards its output (> /dev/null 2>&1 || true). Because forecastDownloadUsageArtifact skips re-downloading artifacts already on disk, the main forecast step reads from the local cache and completes in seconds. --timeout on the main step was reduced to 10 minutes accordingly.

@pelikhan
pelikhan marked this pull request as ready for review July 28, 2026 20:15
Copilot AI review requested due to automatic review settings July 28, 2026 20:15
@pelikhan
pelikhan merged commit 0c18a16 into main Jul 28, 2026
@pelikhan
pelikhan deleted the copilot/aw-fix-gh-aw-forecast-timeout branch July 28, 2026 20:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Parallelizes forecast artifact downloads to prevent long-running forecasts from timing out.

Changes:

  • Adds bounded concurrent artifact loading and a --concurrency flag.
  • Adds concurrency and cancellation tests.
  • Updates the daily forecast workflow with prefetching and shorter timeouts.
Show a summary per file
File Description
pkg/cli/forecast_compute.go Implements parallel artifact loading.
pkg/cli/forecast_command.go Adds concurrency configuration and flag.
pkg/cli/forecast_test.go Tests parallel loading and flag registration.
.github/workflows/daily-spending-forecast.md Adds artifact prefetching and concurrency settings.
.github/workflows/daily-spending-forecast.lock.yml Recompiles the workflow.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 5/5 changed files
  • Comments generated: 3
  • Review effort level: Medium

samples := make([]ForecastRunSample, 0, len(completed))

// Download usage artifacts in parallel, then process results in run order.
aicMap := parallelLoadRunAICs(ctx, completed, config)
Comment thread pkg/cli/forecast_test.go
Comment on lines +494 to +495
got := parallelLoadRunAICs(context.Background(), runs, ForecastConfig{DownloadConcurrency: 3})
assert.Equal(t, wantAIC, got)
cmd.Flags().Int("sample", 100, "Maximum number of completed runs to sample per workflow")
cmd.Flags().Bool("eval", false, "Evaluate forecast quality against past data (backtesting mode)")
cmd.Flags().Int("timeout", 0, "Gracefully stop forecast computation after this many minutes (0 = no timeout)")
cmd.Flags().Int("concurrency", 0, "Maximum number of concurrent usage-artifact downloads (0 = use default)")
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.83.5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[aw-failures] [aw-fix] P0: Daily Spending Forecast — gh-aw forecast --days 30 times out after 45m during artifact download

3 participants