Skip to content

Restore dependency and wrapper caches concurrently #1171

Description

@brunoborges

Description:
Restore the main dependency cache and independent build-tool wrapper caches concurrently.

Today src/cache.ts restores the main Maven or Gradle dependency cache first, then restores each additional wrapper cache sequentially. These cache entries have independent keys and paths:

  • Maven dependencies: ~/.m2/repository
  • Maven Wrapper: ~/.m2/wrapper/dists
  • Gradle dependencies: ~/.gradle/caches
  • Gradle Wrapper: ~/.gradle/wrapper

Their key computation and downloads do not depend on one another, so the restore path can run them concurrently. The expected wall time should approach the duration of the slower restore instead of the sum of both restores.

Suggested approach:

  1. Compute the main and applicable additional-cache keys concurrently.
  2. Persist each computed key to action state before starting its restore.
  3. Restore independent cache entries concurrently, for example with Promise.all.
  4. Preserve the existing cache-hit and cache-primary-key outputs for the main dependency cache.
  5. Preserve current behavior when an optional wrapper key has no matching dependency file.
  6. Keep cache uploads sequential initially. Parallel uploads should be evaluated separately because compression and network contention could increase post-job time or runner resource usage.

Acceptance criteria:

  • Maven dependency and Maven Wrapper cache restores run concurrently when both apply.
  • Gradle dependency and Gradle Wrapper cache restores run concurrently when both apply.
  • sbt behavior remains unchanged because it currently has no additional wrapper cache.
  • A missing optional wrapper configuration still skips only the wrapper cache.
  • Restore failures retain existing error behavior and do not become silent successes.
  • Main-cache outputs and all restore/save state remain correct regardless of completion order.
  • Unit tests prove that restore operations are started before either independent operation resolves, rather than only asserting call counts.
  • End-to-end coverage confirms both caches restore successfully for Maven and Gradle.
  • Benchmarks compare sequential and concurrent restore wall time using representative small and large cache entries across Linux, macOS, and Windows.

Justification:
The action currently serializes independent network-bound work. Projects using Maven or Gradle wrappers can pay for two cache lookups and downloads back-to-back during every cache-enabled job. This adds directly to job duration and billed runner time.

Wrapper caches were intentionally separated from volatile dependency caches so they survive build-file changes. That reliability improvement introduced a second independent cache operation; executing both restores concurrently should retain the improved cache reuse while reducing its setup-time overhead.

This should be treated as a measured optimization. The implementation should record benchmark results and confirm that concurrent downloads do not regress constrained or self-hosted runners before changing behavior broadly.

Are you willing to submit a PR?
Yes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions