actions / cache

Cache dependencies and build outputs in GitHub Actions
MIT License
4.56k stars 1.21k forks source link

Cache Incompatibility Between ARC and Non-ARC Runners in GitHub Actions #1440

Open GeunSam2 opened 3 months ago

GeunSam2 commented 3 months ago

Description

There is a cache compatibility issue between ARC (Action Runner Controller) runners and non-ARC runners in GitHub Actions. Caches created by ARC runners cannot be restored by non-ARC runners, and vice versa. This issue limits the interoperability between different runner environments, causing inefficiencies in workflows that utilize both ARC and non-ARC runners.

Steps to Reproduce

  1. Scenario 1: Non-ARC to ARC

    • First Job: Non-ARC Runner (e.g., Self-hosted, github hosted ...)

      jobs:
      build:
       runs-on: self-hosted
       steps:
         - uses: actions/checkout@v4
      
         - name: Generate Cache
           id: generate-cache
           run: |
             mkdir -p ./path/to/cache
             echo "This is a test cache" > ./path/to/cache/test.txt
      
           - name: Save Cache
             uses: actions/cache/save@v4
             with:
               path: ./path/to/cache
               key: cache-${{ github.run_id }}
               enableCrossOsArchive: true
    • Second Job: ARC Runner

      jobs:
      test:
       needs: build
       runs-on: k8s-ubuntu-x64-4cores
       steps:
         - uses: actions/checkout@v4
      
         - name: Restore Cache
           id: restore-cache
           uses: actions/cache/restore@v4
           with:
             path: ./path/to/cache
             key: cache-${{ needs.build.outputs.cache-key }}
             restore-keys: cache-
             enableCrossOsArchive: true
      
         - name: Check Cache
           run: |
             if [ -f "./path/to/cache/test.txt" ]; then
               echo "Cache restored successfully"
             else
               echo "Cache not found"
             fi
  2. Scenario 2: ARC to Non-ARC

    • First Job: ARC Runner

      jobs:
      build:
       runs-on: k8s-ubuntu-x64-4cores
       steps:
         - uses: actions/checkout@v4
      
         - name: Generate Cache
           id: generate-cache
           run: |
             mkdir -p ./path/to/cache
             echo "This is a test cache" > ./path/to/cache/test.txt
      
           - name: Save Cache
             uses: actions/cache/save@v4
             with:
               path: ./path/to/cache
               key: cache-${{ github.run_id }}
               enableCrossOsArchive: true
    • Second Job: Non-ARC Runner

      jobs:
      test:
       needs: build
       runs-on: self-hosted
       steps:
         - uses: actions/checkout@v4
      
         - name: Restore Cache
           id: restore-cache
           uses: actions/cache/restore@v4
           with:
             path: ./path/to/cache
             key: cache-${{ needs.build.outputs.cache-key }}
             restore-keys: cache-
             enableCrossOsArchive: true
      
         - name: Check Cache
           run: |
             if [ -f "./path/to/cache/test.txt" ]; then
               echo "Cache restored successfully"
             else
               echo "Cache not found"
             fi

Expected Behavior

The cache should be successfully restored across different runner environments.

Actual Behavior

The cache fails to restore, displaying a "Cache not found" message, despite the cache being available and correctly generated.

Additional Information

Environment Details

Impact

This issue limits the flexibility and interoperability of using different runner types within the same workflow, leading to inefficiencies and potential workflow redesign to avoid mixed runner environments.

sb185296 commented 2 months ago

i have same problem ! what we can do to fix it ???

vlad-oj commented 2 months ago

I suppose it has the same nature as described here https://github.com/actions/cache/issues/1455#issuecomment-2328358604

deitch commented 1 month ago

The problem, I believe, is here:

  const workspace = process.env['GITHUB_WORKSPACE'] ?? process.cwd()
  const globber = await glob.create(patterns.join('\n'), {
    implicitDescendants: false
  })

  for await (const file of globber.globGenerator()) {
    const relativeFile = path
      .relative(workspace, file)
      .replace(new RegExp(`\\${path.sep}`, 'g'), '/')
    core.debug(`Matched: ${relativeFile}`)

It uses path.relative() to resolve file relative to workspace, but that is not what path.relative does. The docs state:

The path.relative() method returns the relative path from from to to based on the current working directory. If from and to each resolve to the same path (after calling path.resolve() on each), a zero-length string is returned.

It is doing the relative path to something based on the current working directory. Here is a simple test.

$ mkdir /tmp/foo && cd /tmp/foo
$ node
> path.relative("/a/b/c", "../q")
'../../../tmp/q'

I think they were looking for ../q, i.e. "q as relative to /a/b/c, and not "how do I get to q relative to abc given my current working directory?"

I should open an issue there, or make a dedicated one here.