actions / cache

Cache dependencies and build outputs in GitHub Actions
MIT License
4.49k stars 1.2k forks source link

Why can't it skip the cache write if the operation failed? #1230

Closed octogonz closed 1 year ago

octogonz commented 1 year ago

A simple example:

name: ci-single.yml
on:
  workflow_dispatch:
jobs:
  build:
    name: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 2

      - uses: actions/setup-node@v3
        with:
          node-version: 16

      - name: Cache the PNPM store
        uses: actions/cache@v3
        with:
          path: ~/.rush-pnpm-store
          key: ${{ runner.os }}-pnpm-${{ hashFiles('common/config/rush/pnpm-lock.yaml') }}-v1001
          # If we can't find a match, restore the latest cache entry
          restore-keys: |
            ${{ runner.os }}-pnpm-

      - name: Set RUSH_PNPM_STORE_PATH
        run: echo "RUSH_PNPM_STORE_PATH=~/.rush-pnpm-store" >> $GITHUB_ENV

      - name: Rush Install
        run: node common/scripts/install-run-rush.js install

Good situation

  1. There is a cache miss
  2. We run rush install
  3. The "Post" action writes ~/.rush-pnpm-store to the cache

And on the next run:

  1. There is a cache hit
  2. We run rush install and it goes much faster
  3. The "Post" action does nothing

Bad situation with apparently no solution

  1. There is a cache miss
  2. We run rush install and it fails right away (for example, a config file has a syntax error)
  3. The "Post" action writes a completely empty ~/.rush-pnpm-store to the cache

And now for the next 7 days, every run goes like this:

  1. There is a cache hit, which restores an empty folder
  2. We run rush install and it is extremely slow
  3. The "Post" action does nothing

Is the magical "Post" action even a good design?

This would be easy to solve if the cache read/write were separate steps.

Hypothetical Example

name: ci-single.yml
on:
  workflow_dispatch:
jobs:
  build:
    name: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 2

      - uses: actions/setup-node@v3
        with:
          node-version: 16

      - name: READ the PNPM store
        uses: actions/cache@v3
        with:
          mode: read-only  # πŸ‘ˆπŸ‘ˆπŸ‘ˆ
          path: ~/.rush-pnpm-store
          key: ${{ runner.os }}-pnpm-${{ hashFiles('common/config/rush/pnpm-lock.yaml') }}-v1001
          # If we can't find a match, restore the latest cache entry
          restore-keys: |
            ${{ runner.os }}-pnpm-

      - name: Set RUSH_PNPM_STORE_PATH
        run: echo "RUSH_PNPM_STORE_PATH=~/.rush-pnpm-store" >> $GITHUB_ENV

      - name: Rush Install
        run: node common/scripts/install-run-rush.js install

      - name: WRITE the PNPM store
        uses: actions/cache@v3
        with:
          mode: write-only  # πŸ‘ˆπŸ‘ˆπŸ‘ˆ
          path: ~/.rush-pnpm-store
          key: ${{ runner.os }}-pnpm-${{ hashFiles('common/config/rush/pnpm-lock.yaml') }}-v1001
          # If we can't find a match, restore the latest cache entry
          restore-keys: |
            ${{ runner.os }}-pnpm-

Benefits:

Are there workaround?

actions/cache@v3 introduced a confusingly named setting lookup-only that sounds like it disables the post write:

  • lookup-only - If true, only checks if cache entry exists and skips download. Does not change save cache behavior. Default: false

But actually disables the read, not the write.

As far as I can tell, there is absolutely no way to use actions/cache to read from the cache without saving something.

Why is it designed like that? Should we improve it?

octogonz commented 1 year ago

Closing because I didn't read the manual to find: 😁

https://github.com/actions/cache/blob/main/save/README.md

https://github.com/actions/cache/blob/main/restore/README.md