MJHD

エモさ駆動開発

Github Actionsのcacheをデータの永続化(?)に使う

Github Actionsでワークフローを作るとき、「どこかにデータを保存して次の実行時に参照したいな」「別のワークフローとデータを共有したいな」と思ったことはないでしょうか。

実は、普段キャッシュ用途に使っている actions/cache を使うと、制限付きでこの辺りが実現できます。

actions/cache

actions/cache は任意の文字列(key)を使って、指定ディレクトリや指定ファイルを保存し、任意の文字列(restore-keys)を使って復元できる仕組みです。

主に依存インストールのキャッシュやビルドのキャッシュに使われていますが、この仕組みをもっと汎用的に考えればデータの永続化(?)にも使えます。

制限

actions/cache には以下の制限があります:

  • レポジトリ全体で10GBまで(2022/6/4現在)
  • 保持期間は7日間

この条件を満たさないものは、古いものから順に削除されていきます。

なのでこの記事が適用できるのは、例えば決まった曜日にscheduleで実行されるWorkflowで7日以上間隔が空かないものや、一定期間過ぎたらリセットされても問題ないものになります。

(私は、月曜と木曜にメンバーを輪番で指名するWorkflowのために使用しています)

Starカウンター

簡単な例としてレポジトリにスターが付くたびにインクリメントするWorkflowを考えてみましょう。

on句にwatchを指定することでスターが付くたびにWorkflowが実行されます。あとは、cacheを使って現在のスター数をインクリメントしていけば、なんとなくカウントできそうです。

Github API叩けばスター数取れるじゃんというのは一旦置いておきましょう)

name: Star Counter

on:
  watch:
    types: [started]

env:
  STATE_FILE: './state'

jobs:
  increment:
    runs-on: ubuntu-20.04
    steps:
      - name: IDの生成
        id: build-id
        run: echo "::set-output name=id::$(date +%s)"

      - uses: actions/cache@v3
        id: state
        with:
          path: ${{ env.STATE_FILE }}
          key: counter-${{ steps.build-id.outputs.id }} # 毎回、最新のキャッシュを保存するためにIDを指定する
          restore-keys: counter- # 復元時は最新のキャッシュを指定する

      - name: 初回ならカウンターを初期化
        run: |
          if [ ! -f ${{ env.STATE_FILE }} ]; then
            echo '0' > ${{ env.STATE_FILE }}
          fi

      - name: カウンターをインクリメントする
        run: |
          VALUE=$(cat ${{ env.STATE_FILE }})
          echo "CURRENT: $VALUE"
          echo "$((VALUE + 1))" >| ${{ env.STATE_FILE }}

これを実行すると、以下のように実行されるたびに前回の状態を復元し、インクリメントするWorkflowが実現できます。

カウンターがインクリメントされている様子

その他の可能性

まだ試していませんが、Workflowが同時に走らないという前提があれば、このキャッシュを通じて他のWorkflowとも値を共有できます。

このキャッシュは「ブランチ」と「key」のスコープで共有されるため、同じ「key」を指定すれば同じデータが見れるはずです。

Workflowが同時に走りうる場合は不整合が起きるので、トリガーがscheduleで1日おきに動かすWorkflowなどだったら安全に扱えるのではと思っています。

https://github.com/actions/cache#cache-scopes

まとめ

制限はあるが、actions/cache を使ってデータの永続化(?)ができる。 簡単なWorkflowなら、Workflow間の状態を持たせることができる。