GitHub Actionsがdependabotで発火した場合のみ挙動を変えたい

DependabotのPRを元に発火するGitHub Actionsはread-onlyなGITHUB_TOKENのみを扱うことができるため、step内で Secretsを参照している場合はfailしてしまいます。

【Github actions】DependabotのPull RequestでSecretsが参照できずワークフローがFailになった場合の対処 - Simple minds think alike

failしていると煩わしいので、dependabotで発火した場合はそもそもジョブを実行しないようにするか pull_request_targetworkflow_run を使うようにすると良さそうです。 今回はdependabotで発火した場合は、ジョブを実行しないようにするワークフローを例として残しておきます。

name: example

on:
  push:

jobs:
  verify-actor:
    runs-on: ubuntu-latest
    outputs:
      actor: ${{ steps.echo.outputs.actor }}
    steps:
      - name: echo actor
        id: echo
        run: |
          echo "::set-output name=actor::${{ github.actor }}"
  

  trigger_deploy:
    runs-on: ubuntu-latest
    needs: [verify-actor]
    if: needs.verify-actor.outputs.actor != 'dependabot[bot]'
    steps:
      - uses: actions/checkout@v2

      - name: something
        run: |
          echo "hey"

一つのジョブ内で条件分岐をしようとすると、全てのstepにifを入れないといけません。 そのため、最初に条件分岐をするためだけのジョブを作り、後続のジョブの ifneedsoutputs を参照することで 条件文の記述を1回にしています。

stepの出力を後続stepから参照する場合は、echo "::set-output name=key::value 形式で参照できるようにしておく必要がありますが、 jobの出力を後続jobから参照する場合は、jobのoutputsneeds を使う必要があります。(ややこしい)

参考

【Github actions】DependabotのPull RequestでSecretsが参照できずワークフローがFailになった場合の対処 - Simple minds think alike

GitHub Actions でモノレポ上の変更があったプロジェクトだけテストを走らせる

GitHub ActionsでJobのOutputの値を後続Jobで参照する - notebook

ECSでunicornを動かすときの注意点

ECSはタスクが停止すると、各コンテナにまず SIGTERM を送ります。 しかし、Railsと一緒によく使われるunicornSIGTERM を受け取ると、gracefulに終了してくれません。

graceful shutdownさせるためには QUITシグナルをmasterプロセスに対して送る必要があります。 Signal handling

aws.amazon.com

デフォルトの停止シグナルは SIGTERM ですが、これは Dockerfile に STOPSIGNAL ディレクティブを追加することによってオーバーライドできます。この停止シグナルは、シャットダウンの命令をアプリケーションに通知します。

やり方としてはshell scriptのハンドラーを書いたり、STOPSIGNAL ディレクティブをDockerfileに追加する方法もあると思いますが、今回の場合は unicorn.rbSignal.trap して自身のmasterプロセスに対してシグナルを送るのが一番簡単だと思います。

before_fork do |server, worker|
  Signal.trap 'TERM' do
  Process.kill 'QUIT', Process.pid
end

参考

Nginx の limit_req

Nginxの流量制限する場合に使用される limit_req の使い方について調べてみました。 NGINX Rate Limiting の簡単なメモになります。

limit_req

Nginxのrate limitでは、パケット通信の帯域制限などで使われているleaky bucket algorithmに従ってキューイングします。

基本的な設定

http {
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

    ...

    server {

        ...

        location /search/ {
            limit_req zone=one burst=5;
        }

ひとつずつ設定を見ていきます。

まず、limit_req_zone directive で httpリクエストに対する制限を定義できます。 ここではあくまでも定義しているだけなので、実際に実装する場合は location ディレクティブ内などに設定を書く必要があります。 limit_req_zone は key、zone、rateという3つのパラメーターを持ちます。

key

その右にある $binary_remote_addr はクライアントのIPアドレスを表現するNginxの変数です。

zone

アクセス制限のかけたURLに対して頻繁にアクセスしてくるそれぞれのIPアドレスを記録するためのメモリについての設定です。 これはNginxのワーカープロセス間で共有されます。 目安として1メガバイトには約16,000のIPアドレスを記録することが可能です。 Nginxが新しいIPアドレスを記録する必要があるときにメモリが枯渇している場合は、最も古いIPアドレスを削除し、メモリを開放します。 それでもまだスペースが足りず不十分な場合は503を返します。 また、上記の枯渇問題を防ぐためにNginxは新しいIPアドレスを登録するたびに過去60秒間に使用されていない最大2つのエントリを削除します。

rate

最大のリクエストレートを設定します。 上記の例では、1秒あたり1リクエストを超えることができないことを表していますが、 実際にはNginxはミリ秒の粒度でリクエストを追跡するため100msごとに1つのリクエストに対応します。

burst

burst パラメーターをzoneで指定されたrateを超えてクライアントが実行できるリクエストの数を定義できます。 burstを超えたリクエストは全てキューイングされます。

例: 20スロットが空でリクエストが21個飛んできた場合は、1つをアップストリームに流す。 次に残りの20リクエストをキューイングし、100ミリ秒ごとにデキューする。

burst with nodelay

nodelay が設定された場合は空きスロットがない状態は503、 空きスロットがある場合はリクエストは処理され、スロットが使用済みになります。

例: 20スロットが空でリクエストが21個同時に飛んできた場合は、21リクエスト全て処理をし、20個のスロットを確保する。 その後、100ミリ秒ごとにデキューして消化。

まとめ

burstなし、burstあり、burstあり+nodelayの3パターンあります。

本番環境で使う場合は nodelay をつける場合が多そう。

参考

Goで自作パッケージを作るときのちょっとした動作確認

SongmuさんのGo Conference 2019 Summerでの発表資料に

パッケージ内の関数の動作確認とかは gore -pkg . が異常に便利です

と書いてあって、使ってみたら結構便利だったので備忘録として残しておきます。

  -pkg string
        the package where the session will be run inside

合わせて読みたい

RFC違反のメールアドレス

日本の大手キャリアであるdocomoauが2009年ごろまでに作成したメールアドレスはRFCに準拠していないものも作成可能でした。 今日はRFC違反のメールアドレスを考慮した正規表現Amazon SES、SendGridの対応状況について調べてみました。

RFC違反のメールアドレスを考慮した正規表現

https://qiita.com/sakuro/items/1eaa307609ceaaf51123

HTML5input[type=email] と同じ正規表現をかけると良いです。

Amazon SES

blog.serverworks.co.jp

検証結果を見る限り、RFC違反のメールアドレスでも送れるものと送れないものがあるみたいです。

SendGrid

2013年頃はRFC違反のメールアドレスでも一部送れるようだったが、2019年に仕様が代わり ローカルパートをダブルクォーテーションで囲まないといけないらしいです。

合わせて読みたい

git 備忘録

任意のコミットで変更されたファイルの一覧を出力する

通常のコミット: git diff-tree --no-commit-id --name-only -r <tree-ish>

マージコミット: git log -m -1 --name-only --pretty="format:" <commit-id>

mainブランチにマージ済みのブランチを削除する

git branch --merged main | grep -v '^\*' | xargs -n 1 git branch -d

フラーをやめて、READYFORに入る。

1月末でフラーを退職して、2月頭からREADYFORで働いています。

Ruby / Rails をしっかり書くのは初めてなので、色々触りながら「う〜ん、これはいかんな・・・」とか試行錯誤してる毎日です。

転職の決めて

VP of Engineeringの伊藤さん からスカウトをいただき、転職しました。

個人的にはガバナンスが効いており、CTOやVPoE、EMなどの技術経営やマネジメントをするポジションが確立されているというのが大きな決め手となりました。

エンジニアの人数が一年で2倍に!CTOに聞く、サービスの未来を描ける技術組織のつくり方|READYFOR note  

想定外のイベントを前向きに楽しむ

READYFORで働くことは紛れもなく偶然なんですが、 前向きにチャレンジすることで自分にとってプラスとなる機会をたくさんつくろうと思います。

思いがけない出来事がキャリアに大きな影響を与えることを計画的偶発性理論(Planned Happenstance)等といったりするらしいですが、 現職ではこれを体験してみたいなと思っています。偶然の出会いやご縁こそ大切にしたいものです。

社会的な問題を解決する

コロナ基金のプロジェクトがREADYFOR史上最大の支援額になったりしており、サービスのインパクトと使命感を感じています。 創業当初のRailsのコードベースが結構でかいんですが、今のシステムにそぐわないものも当然あるわけでそういう箇所に アグレッシブに手を加えていけたらいいなと思っています。

これから

という感じでREADYFORはエンジニアリング組織に対して理解のある会社です。

エンジニアが毎月入社しており、急成長段階で面白いフェーズだと思っています。 一皮剥けるように頑張ります。

皆様READYFORをよろしくお願いいたします。