2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

CircleCIのparallelismと2.1からの新機能を使ってスッキリと並列化する

Posted at

概要

私の担当するサービスでは、CircleCIによる自動テストを行っています。

最近、実行時間が伸びてきた事もあり、CircleCIの parallelism という並列実行数の設定項目と、Version 2.1 からの新機能 ( 2018年頃のリリースなので別にではないけど )である commands parameters executors を使って、今まで直列1本で行っていたCircleCIのテストのビルドを並列化して実行時間を10分→4〜5分程度に短くしてみたのでその際の情報を共有します。

いざ、ymlファイルに並列的な書き方をしようとすると、たくさんの重複記述を書く必要が出てしまい、可読性もテンションも下がってしまいます。そこで、

  • executors 項目に実行環境設定( machine: true )をまとめて、複数のジョブで再利用する
  • commands に何度も出てくるコマンドをまとめて名前をつけて、ステップ内から呼び出す際に再利用する
  • parameters オプションを使って commands のコマンドに渡すパラメータの名前や型を定義して可読性を上げる

を行い、その後

  • parallelism を任意の数値に設定し、テスト対象のファイルをCircleCIの仕組みを使って よしなに 分割し実行する

をしました。

例 (雰囲気)

もともと、build というjob一本で直列に実行していたものを

version: 2
jobs:
  build:
    machine: true
    working_directory: ~/work
    steps:
      - checkout
      - run:
          name: Execute test 1
          command: |
             echo "You can execute any command"
      - run:
          name: Execute test 2
          command: |
            ./test-runner --files \
            app/tests/cases/models \
            app/tests/cases/controllers
workflows:
  version: 2
  my-build:
    jobs:
      - build

↓こうした。

version: 2.1
executors:
  my-executor:
    machine: true
commands:
  my_command_1:
    steps:
      - run:
          name: Execute test 1
          command: |
             echo "You can execute any command"
  my_command_2:
    parameters:
      target:
        type: string
    steps:
      - run:
          name: Execute test 2
          command: |
            ./test-runner --files << parameters.target >>
 jobs:
  my-unittest-job:
    executor: my-executor
    parallelism: 3
    steps:
      - checkout
      - my_command_1:
      - my_command_2:
          target: |
            $(circleci tests glob \
            "app/tests/cases/{models,controllers}/**/*.test.php" \
            | circleci tests split --split-by=filesize
workflows:
  version: 2
  my-build:
    jobs:
      - my-unittest-job

コマンドを別途定義するので、このサンプルだと変更後の方が記述量が増えているが、実際はもっとたくさんのジョブやステップが存在しているので、この対策を行わないとコピペに次ぐコピペで大変なことになる。

parameters について

コマンド側で parameters の中にパラメータ名と型、デフォルト値、説明書きを定義することが出来る。
また、実際のコマンド実行の中では << parameters.パラメータ名 >> という形で取り出すことが出来る。
https://circleci.com/docs/2.0/reusing-config/#parameter-syntax

commands:
# ...略...
  my_command_2:
    parameters:
      tekitouna-parameter-name:
        description: Tekitou na setsumei.
        type: string
        default: "FUGA"
    steps:
      - run:
          command:  echo << parameters.tekitouna-parameter-name >>

呼び出し側は、以下のように実行するコマンドにパラメータをセットすることが出来る。

 jobs:
  my-unittest-job:
   steps:
      - my_command_2:
          tekitouna-parameter-name: HOGE

CircleCIの仕組みを使って よしなに 分割し実行する、件

https://circleci.com/docs/2.0/parallelism-faster-jobs/ によると、circleci tests コマンドにて glob を使って対象となるファイル名を取得した後に、split に渡す事で、parallelism: 3 のように指定した並列実行の数に分割してくれる様子。
--split-by には filesize (ファイルのサイズでよしなに分割)とtiming (過去の実行時間の実績を元によしなに分割)があるようで、timing のほうが filesizeより更に最適化出来るようだが、設定が若干面倒そうだったので、今回はやめておいた。

circleci tests glob "**/*.go" | circleci tests split --split-by=filesize

サンプルでも、以下のようにテストランナーにテスト対象のファイル名を渡すようにしている。

target: |
  $(circleci tests glob \
  "app/tests/cases/{models,controllers}/**/*.test.php" \
  | circleci tests split --split-by=filesize

苦労した点

今まで直列に、固定された順序で実施されていたため、 たまたま運良く通っていたテスト というのが存在していたが、それらが並列化したタイミングでFailするようになってしまった。そういうのが複数箇所、複数原因あり、特定してテスト側を修正するのが悲しかった。例えば↓の様に a→bの順番で実行されていたからbでrequireしなくても動いてたが、並列化によって実行グループが変わったために b で someFunc() なんて知らない、と怒られたり。

a.test.php
require_once "./functions.php"

someFunc();
b.test.php
someFunc();

参考

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?