- 機能フラグを使用するタイミング
- GitLab 開発における機能フラグ
- メインブランチが壊れるリスク
- 機能フラグの種類
- 機能フラグの定義と検証
- 新しい機能フラグの作成
- すべての機能フラグのリスト
- 機能フラグの切り替え
- 機能フラグの削除
- 機能フラグを使った開発者
- チェンジログ
- テストの機能フラグ
- 機能フラグによるSidekiqワーカーの動作制御
GitLab開発における機能フラグ
この文書は、機能フラグの内部使用を改善するためのエピックとして、継続的な作業の対象です。提案があれば、新しいイシューとして提起し、エピックに添付してください。
機能フラグのライフサイクルの概要や、機能フラグを使うべきかどうかの判断にお困りの場合は、機能フラグのライフサイクルハンドブックのページをご覧ください。
機能フラグを使用するタイミング
ハンドブックの「機能フラグを使用する場合」に移動しました。
GitLab 開発における機能フラグ
機能フラグを活用するかどうかを決める際には、以下の点を考慮する必要があります:
- 機能フラグはデフォルトで無効でなければなりません。
- 機能フラグのアカウンティングの必要性を減らすために、機能フラグはできるだけ短い期間コードベースに残すべきです。
- 機能フラグをオペレーションする人は、機能フラグの背後にある機能のステータスを、ドキュメントや他の利害関係者に明確に伝える責任があります。機能フラグが必要であることが明らかになり次第、イシューの説明を機能フラグ名とデフォルトのオン/オフで更新する必要があります。
- 機能フラグを導入したり、その状態を更新したり、機能が安定したと判断して既存の機能フラグを削除したりするマージリクエストには、~"機能フラグ "ラベルを付ける必要があります。
機能の実装が複数のマージリクエストにまたがって提供される場合:
- フラグを使用する最初のマージリクエストで、デフォルトでオフになる新しい機能フラグを作成してください。フラグを個別に追加すべきではありません。
- 機能フラグがオンの場合にのみ新しいコードが追加されるように、1つ以上のマージリクエストでインクリメンタルな変更を提出してください。開発者のローカルGDKでは、機能フラグを有効にしておくことができます。
- 機能が他のチームメンバーによってテストされる準備ができたら、最初のドキュメントを作成します。機能フラグの状態についての詳細を含めてください。
- 特定のプロジェクトで機能フラグを有効にし、実装にイシューがないことを確認してください。
gitlab
のような公開プロジェクトでは、ドキュメントがない場合は機能フラグを有効にしないでください。チームメンバーや貢献者は、公開プロジェクトで機能フラグが有効になっているのを見たら、その機能の使い方のドキュメントを探すかもしれません。 - その機能を本番環境で使用できるようになったら、マージリクエストを次の宛先に送ってください:
- 最新のフラグステータスを説明するためにドキュメントを更新してください。
- 変更履歴を追加しました。
- 機能フラグをデフォルトでオンにするか、完全に削除して新しい動作を有効にします。
機能フラグがあると、機能のリリースが少なくとも1ヶ月(=1リリース)遅れると考えたくなるかもしれません。そうではありません。機能フラグは特定の期間 (たとえば最低でも 1 リリース) 存在する必要はありません。安定とは、GitLab.com上で機能停止などの問題を起こすことなく動作することを意味します。
メインブランチが壊れるリスク
機能フラグは、それを導入した MR で使用しなければなりません。そうしないと、rspec:feature-flags
ジョブがmain
ブランチでのみ実行されるため、メインブランチが壊れるというシナリオが発生します。
機能フラグの種類
想定される使用方法に合った機能フラグの種類を選択してください。
development
タイプ
development
機能フラグは短命の機能フラグで、未完成のコードを本番環境にデプロイするときに使います。GitLab で使われる機能フラグのほとんどはdevelopment
型です。
development
機能フラグには、機能フラグロールアウトテンプレートから作成されたロールアウトイシューが必要です。
development
機能フラグのフォーマットはFeature.<state>(:<dev_flag_name>)
です。これらを有効/無効にするには、GitLab Railsコンソールで実行します:
# To enable it for the instance:
Feature.enable(:<dev_flag_name>)
# To disable it for the instance:
Feature.disable(:<dev_flag_name>)
# To enable for a specific project:
Feature.enable(:<dev_flag_name>, Project.find(<project id>))
# To disable for a specific project:
Feature.disable(:<dev_flag_name>, Project.find(<project id>))
development
機能フラグの状態を確認するには:
# Check if the feature flag is enabled
Feature.enabled?(:dev_flag_name)
# Check if the feature flag is disabled
Feature.disabled?(:dev_flag_name)
development
機能フラグの場合、タイプを指定する必要はありません(デフォルトのタイプです)。
ops
タイプ
ops
機能フラグは、GitLab製品の動作のオペレーション面を制御する長期間の機能フラグです。例えば、Sidekiqワーカーの動作など、パフォーマンスに影響を与える可能性のある機能を無効にする機能フラグです。
ops
機能フラグは、いつ有効になったり無効になったりするのかを予測するのが難しいので、ロールアウトの問題はないでしょう。
ops
機能フラグを呼び出すには、type: :ops
:
# Check if feature flag is enabled
Feature.enabled?(:my_ops_flag, project, type: :ops)
# Check if feature flag is disabled
Feature.disabled?(:my_ops_flag, project, type: :ops)
# Push feature flag to Frontend
push_frontend_feature_flag(:my_ops_flag, project, type: :ops)
experiment
タイプ
experiment
機能フラグはGitLab.comのA/Bテストに使用されます。
experiment
機能フラグは、development
機能フラグと同じ標準に準拠しなければなりませんが、インターフェイスに若干の違いがあります。実験機能フラグには、実験トラッキングテンプレートを使って作成したロールアウトイシューが必要です。詳細は実験ガイドをご覧ください。
worker
タイプ
worker
機能フラグは、Sidekiqジョブの延期など、Sidekiqワーカーの動作を制御するために使用されます。
worker
run_sidekiq_jobs_AuthorizedProjectsWorker
機能フラグは、ワーカー名そのものを使って動的に生成されるため、YAML定義はありません。worker
タイプの機能フラグを使用するいくつかの例が、Sidekiqジョブの延期にあります。
機能フラグの定義と検証
GitLab 13.3 で導入されました。
開発中(RAILS_ENV=development
)またはテスト中(RAILS_ENV=test
)、すべての機能フラグの使用は厳密に検証されます。
このプロセスは、コードベースにおける機能フラグの一貫した使用を保証するためのものです。すべての機能フラグは、次のようにしなければなりません:
- 既知であること。明示的に定義された機能フラグのみを使用すること。
- 二重に定義しないこと。FOSSかEEのどちらかで定義されなければなりませんが、両方で定義することはできません。
- 全ての呼び出しにおいて有効で一貫性のある
type:
を使用してください。 - オーナーを持つこと。
GitLab が知っている機能フラグはすべて、YAML ファイルに格納されています:
それぞれの機能フラグは、いくつかのフィールドからなる個別の YAML ファイルで定義されています:
項目 | 必須 | 説明 |
---|---|---|
name | yes | 機能フラグの名前。 |
type | yes | 機能フラグの種類。 |
default_enabled | yes | 機能フラグのデフォルト状態。 |
introduced_by_url | いいえ | 機能フラグを導入したマージリクエストのURL。 |
rollout_issue_url | いいえ | 機能フラグのロールアウトに関するイシューのURL。 |
milestone | いいえ | 機能フラグが作成されたマイルストーン。 |
group | いいえ | 機能フラグを所有するグループ。 |
RAILS_ENV=production
で実行すると、すべてのバリデーションがスキップされます。新しい機能フラグの作成
GitLabコードベースは、新しい機能フラグ定義を作成するための専用ツールbin/feature-flag
。このツールは新しい機能フラグについて様々な質問をし、config/feature_flags
もしくはee/config/feature_flags
にYAML定義を作成します。
YAML 定義ファイルを持つ機能フラグのみが、開発環境やテスト環境で使用できます。
$ bin/feature-flag my_feature_flag
>> Specify the group introducing the feature flag, like `group::project management`:
?> group::application performance
>> URL of the MR introducing the feature flag (enter to skip):
?> https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38602
>> Open this URL and fill in the rest of the details:
https://gitlab.com/gitlab-org/gitlab/-/issues/new?issue%5Btitle%5D=%5BFeature+flag%5D+Rollout+of+%60test-flag%60&issuable_template=Feature+Flag+Roll+Out
>> URL of the rollout issue (enter to skip):
?> https://gitlab.com/gitlab-org/gitlab/-/issues/232533
create config/feature_flags/development/my_feature_flag.yml
---
name: my_feature_flag
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38602
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/232533
group: group::application performance
type: development
default_enabled: false
新しく導入された機能フラグはすべて デフォルトでは無効です.
機能フラグの後ろで開発されマージされた機能は、変更ログエントリを含めるべきではありません。エントリは機能フラグを削除するマージリクエストか、機能フラグのデフォルト値が有効に設定されているマージリクエストのどちらかに追加されるべきです。その機能にデータベースのマイグレーションが含まれている場合、データベースの変更に関する変更ログエントリを含めるべきです。
--ee
フラグを追加します:bin/feature-flag --ee
新しいフラグの命名
新しい機能フラグの名前を決めるときは、以下のガイドラインを考慮してください:
- 短くてわかりにくい名前よりも、長くて説明的な名前のほうがよいでしょう。
- 名前はスネークケース(
my_cool_feature_flag
)で書きましょう。 -
二重否定で考える(文書化する)ことを避けるため、
disable
を名前に使うことは避けてください。hide_
,remove_
,disallow_
で名前を始めることを検討してください。ソフトウェア工学では、この問題は「ブーリアン変数の否定名」として知られています。しかし、フラグをデフォルトで無効にしたり、フラグの後ろに移動して機能フラグを削除したり、アクターによってフラグを選択的に無効にしたりするために、否定語を完全に禁止することはできません。
マスター(メイン)ブランチが壊れるリスク
rspec:feature-flags
ジョブがmaster
ブランチでのみ実行されるため、壊れた masterシナリオが発生します。すべての機能フラグのリスト
ChatOpsを使用して環境内のすべての機能フラグをSlackに出力するには、run feature list
コマンドを使用します。例えば
/chatops run feature list --dev
/chatops run feature list --staging
機能フラグの切り替え
機能フラグのトグルについての詳細は、変更のロールアウトをご覧ください。
機能フラグの削除
機能フラグの削除については、機能フラグのクリーンアップを参照してください。
機能フラグを使った開発者
GitLabコードベースで機能フラグを使うには、主に2つの方法があります:
バックエンド
機能フラグインタフェースはlib/feature.rb
で定義されています。このインターフェイスは、機能フラグが有効か無効かをチェックするためのメソッド群を提供します:
if Feature.enabled?(:my_feature_flag, project)
# execute code if feature flag is enabled
else
# execute code if feature flag is disabled
end
if Feature.disabled?(:my_feature_flag, project)
# execute code if feature flag is disabled
end
設定されていない機能フラグのデフォルトのふるまいは YAML 定義のdefault_enabled:
によって制御されます。
機能フラグに YAML 定義がない場合、開発環境やテスト環境ではエラーが発生し、運用環境ではfalse
が返されます。
指定しない場合、Feature.enabled?
とFeature.disabled?
のデフォルトの機能フラグタイプはtype: development
です。その他の機能フラグタイプについては、type:
を指定する必要があります:
if Feature.enabled?(:feature_flag, project, type: :ops)
# execute code if ops feature flag is enabled
else
# execute code if ops feature flag is disabled
end
if Feature.disabled?(:my_feature_flag, project, type: :ops)
# execute code if feature flag is disabled
end
config/initializers/*
またはクラス・レベルでFeature
クラスを使用すると、予期しないエ ラーが発生することがあります。このエラーは、機能フラグ・アダプタが依存する可能性のあるデータベースがロード時に存在しないために発生します (特に、新規インストールの場合)。データベースをまったく必要としないアダプタもあります (たとえば HTTP アダプタなど)。機能フラグの設定チェックは、Feature
名前空間で抽象化する必要があります。この方法では、機能フラグが変更されたときにアプリケーションをリロードする必要があります。そのため、本番環境で Web/API/Sidekiq フリートをリロードするよう SRE に依頼する必要があり、変更を完全にロールアウト/ロールバックするには時間がかかります。このような理由から、代わりに環境変数(たとえば、ENV['YOUR_FEATURE_NAME']
)またはgitlab.yml
を使用します。避けるべきパターンの例を示します:
class MyClass
if Feature.enabled?(:...)
new_process
else
legacy_process
end
end
再帰の検出
機能フラグがたくさんある場合、どこで呼び出されるかは必ずしも明らかではありません。ある機能フラグの評価が他の機能フラグの評価を必要とするようなサイクルは避けてください。サイクルが発生すると、そのサイクルは解除され、デフォルト値が返されます。
この再帰検出が正しく機能するように、機能値へのアクセスは常にFeature::enabled?
を通して行い、Feature::get
を低レベルで使用することは避けてください。このような現象が発生した場合、Feature::RecursionError
例外がエラートラッカーに追跡されます。
フロントエンド
UI要素に機能フラグを使用する場合、もしあれば、バックエンドの_コードにも_機能フラグを使用してください。こうすることで、その機能が有効になるまで、絶対にその機能を使うことができないようになります。
ApplicationController
を継承するすべてのコントローラで使用できるpush_frontend_feature_flag
メソッドを使用してください。 このメソッドを使用して、たとえば機能フラグの状態を公開することができます:
before_action do
# Prefer to scope it per project or user, for example
push_frontend_feature_flag(:vim_bindings, project)
end
def index
# ...
end
def edit
# ...
end
機能フラグの状態は、JavaScript で次のように確認できます:
if ( gon.features.vimBindings ) {
// ...
}
JavaScriptの機能フラグの名前は常にキャメルケースなので、gon.features.vim_bindings
。
Vueコンポーネントで機能フラグにアクセスする方法の詳細については、Vueガイドを参照してください。
指定しない場合、push_frontend_feature_flag
のデフォルトの機能フラグタイプはtype: development
です。その他の機能フラグタイプについては、type:
を指定する必要があります:
before_action do
push_frontend_feature_flag(:vim_bindings, project, type: :ops)
end
機能アクター
機能フラグにはアクタを使用することを強くお勧めします。アクタは、特定のプロジェクト、グループ、ユーザーに対してのみ機能フラグを有効にする簡単な方法を提供します。これにより、たとえばアクターに基づいてログやエラーをフィルタリングできるため、デバッグが容易になります。また、gitlab-org
またはgitlab-com
グループで最初に機能を有効にし、他のユーザーには影響を与えないようにすることもできます。
アクターはまた、粘着性のある方法で機能のパーセンテージロールアウトを行う簡単な方法を提供します。1%のロールアウトで特定のアクターが機能を有効にした場合、そのアクターは10%、50%、100%でも機能を有効にし続けることができます。
GitLabは現在、以下のモデルを機能フラグアクターとしてサポートしています:
User
Project
Group
アクタはFeature.enabled?
呼び出しの Feature.enabled?
2番目のパラメータです。Feature.enabled?
.NETのすべての呼び出しで、同じアクター型を一貫して使用する必要が Feature.enabled?
あります。
Feature.enabled?(:feature_flag, project)
Feature.enabled?(:feature_flag, group)
Feature.enabled?(:feature_flag, user)
ステージングやプロダクションのようなGitLabが提供する環境で、ChatOpsを使って機能フラグを選択的に有効/無効にする方法の詳細については、GitLabの開発における機能フラグを参照してください。
本番環境での検証にアクタを使用
ステージング環境は本番環境に似た環境で機能をテストする方法を提供しますが、本番環境に特有のパフォーマンスメトリクスの前後を比較することはできません。Sitespeedレポートのようなツールで機能フラグの下にある新しいコードのメトリクスを明らかにできるようにするために、開発者の機能フラグが有効になっている本番環境のプロジェクトがあると便利です。
Sitespeedで古いコードベースをすでにトラッキングしている場合、このアプローチはさらに有効で、機能フラグのロールアウト前後のパフォーマンスを正確に比較できます。
アクタとして追加オブジェクトを有効化
アクターに基づくフィーチャー・ゲートを使用するには、モデルがflipper_id
に応答する必要があります。たとえば、Foo モデルで有効にするには、次のようにします:
class Foo < ActiveRecord::Base
include FeatureGate
end
include FeatureGate
またはflipper_id
メソッドを公開するモデルだけが、Feature.enabled?
のアクターとして使用できます。
ライセンスされた機能の機能フラグ
ライセンスされた機能名と同じ名前の機能フラグを使用することはできません。これは広く議論され、混乱を招くため削除されました。
ライセンスされた機能をチェックするには、例えば、別の名前で専用の機能フラグを追加し、明示的にチェックします:
Feature.enabled?(:licensed_feature_feature_flag, project) &&
project.feature_available?(:licensed_feature)
機能グループ
フィーチャーグループは、lib/feature.rb
(.register_feature_groups
メソッド内)で静的に定義する必要がありますが、その実装は動的にも可能です(DBへのクエリなど)。
lib/feature.rb
で定義すると、features API のfeature_group
パラメータで、指定したフィーチャーグループのフィーチャーをアクティブにすることができます。
利用可能な機能グループは以下の通りです:
グループ名 | スコープ対象 | 説明 |
---|---|---|
gitlab_team_members | ユーザー | のメンバーであるユーザーに対して、この機能を有効にします。gitlab-com
|
フィーチャーグループはグループ名で有効にできます:
Feature.enable(:feature_flag_name, :gitlab_team_members)
ローカルで機能フラグを有効にする(開発中)
rails コンソール (rails c
) で、以下のコマンドを入力して機能フラグを有効にします:
Feature.enable(:feature_flag_name)
同様に、次のコマンドは機能フラグを無効にします:
Feature.disable(:feature_flag_name)
指定したゲートの機能フラグを有効にすることもできます:
Feature.enable(:feature_flag_name, Project.find_by_full_path("root/my-project"))
ローカルで機能フラグを無効にする(開発中)
Railsコンソールから手動で機能フラグを有効/無効にすると、デフォルト値が上書きされます。このため、フラグのdefault_enabled
属性を変更する際に混乱を招く可能性があります。
機能フラグをデフォルトの状態に戻すには、railsコンソール(rails c
)で以下のようにして無効にします:
Feature.remove(:feature_flag_name)
チェンジログ
エンドユーザーが直接アクセスできない機能(例:その機能を使用する機能)、または間接的にアクセスできない機能(例:バックグラウンドジョブを利用する機能、パフォーマンスの向上、データベースのマイグレーション更新)については、変更履歴の紹介を避けたいと考えています。
- データベースのマイグレーションは、セルフマネージドユーザーがアップグレード前にデータベースの変更を認識する必要があるため、常に間接的にエンドユーザーがアクセスできます。このため、変更ログエントリが必要です。
- デフォルトで無効になっている機能フラグの背後にある変更は、変更ログエントリを持つべきではありません。
- デフォルトで有効になっている機能フラグの背後にある変更は、変更ログエントリを持つべきです。
-
機能フラグ自体の変更 (フラグの削除、デフォルトオンの設定) は、変更ログエントリを 持つべきです。フローチャートを使って、変更ログエントリーのタイプを決定してください。
graph LR A[flag: default off] -->|'added' / 'changed' / 'fixed' / '...'| B(flag: default on) B -->|'other'| C(remove flag, keep new code) B -->|'removed' / 'changed'| D(remove flag, keep old code) A -->|'added' / 'changed' / 'fixed' / '...'| C A -->|no changelog| D - 機能フラグの変更ログは、機能フラグではなく、その機能について記述すべきです。ただし、機能フラグのデフォルトオンが新しいコードで削除された場合は除きます ( 上のフローチャートでは
other
)。 - 機能フラグはバグフィックスやメンテナンス作業のロールアウトにも使うことができます。このシナリオでは、変更履歴はそれに関連したものでなければなりません。たとえば、
fixed
やother
などです。
テストの機能フラグ
機能フラグをコードベースに導入すると、テストすべきコードパスが追加されます。機能フラグの影響を受けるすべてのコードに対して、その機能が正しく動作することを確認するために、有効時と無効時の両方の自動テストを含めることを強く推奨します。自動テストが両方の状態に含まれていない場合は、テストされていないコードパスに関連する機能を、本番環境にデプロイする前に手動でテストする必要があります。
テスト環境を使用する場合、すべての機能フラグはデフォルトで有効になっています。spec/spec_helper.rb
ファイル で、フラグをデフォルトで無効にすることができます。フラグを無効にする必要がある理由をインラインでコメントしてください。可能であれば、参照用にイシューの URL も添付してください。
テストの機能フラグを無効にするには、stub_feature_flags
ヘルパーを使用します。たとえば、ci_live_trace
機能フラグをテスト内でグローバルに無効にするには、次のようにします:
stub_feature_flags(ci_live_trace: false)
Feature.enabled?(:ci_live_trace) # => false
両方のパスをテストする一般的なパターンは、次のようになります:
it 'ci_live_trace works' do
# tests assuming ci_live_trace is enabled in tests by default
Feature.enabled?(:ci_live_trace) # => true
end
context 'when ci_live_trace is disabled' do
before do
stub_feature_flags(ci_live_trace: false)
end
it 'ci_live_trace does not work' do
Feature.enabled?(:ci_live_trace) # => false
end
end
機能フラグがあるアクターでのみ有効で、他のアクターでは有効でないテストを設定したい場合、ヘルパーに渡すオプションでこれを指定できます。たとえば、特定のプロジェクトでci_live_trace
機能フラグを有効にする場合:
project1, project2 = build_list(:project, 2)
# Feature will only be enabled for project1
stub_feature_flags(ci_live_trace: project1)
Feature.enabled?(:ci_live_trace) # => false
Feature.enabled?(:ci_live_trace, project1) # => true
Feature.enabled?(:ci_live_trace, project2) # => false
FlipperGate の動作は次のようになります:
- 指定したアクタのオーバーライドを有効にすることができます。
- 指定したアクタのオーバーライドを無効(削除)にして、デフォルトの状態に戻すことができます。
- 指定したアクタを明示的に無効にしたことをモデル化する方法はありません。
Feature.enable(:my_feature)
Feature.disable(:my_feature, project1)
Feature.enabled?(:my_feature) # => true
Feature.enabled?(:my_feature, project1) # => true
Feature.disable(:my_feature2)
Feature.enable(:my_feature2, project1)
Feature.enabled?(:my_feature2) # => false
Feature.enabled?(:my_feature2, project1) # => true
have_pushed_frontend_feature_flags
have_pushed_frontend_feature_flags
を使用して、push_frontend_feature_flag
が機能フラグを HTML に追加したかどうかをテストします。
例えば、
stub_feature_flags(value_stream_analytics_path_navigation: false)
visit group_analytics_cycle_analytics_path(group)
expect(page).to have_pushed_frontend_feature_flags(valueStreamAnalyticsPathNavigation: false)
stub_feature_flags
対Feature.enable*
テスト環境で機能フラグを有効にするには、stub_feature_flags
。この方法は、単純なユースケースに対して、シンプルでよく記述されたインターフェイスを提供します。
しかし、場合によっては、機能フラグのパーセンテージロールアウトのように、より複雑な動作をテストする必要があります。これには.enable_percentage_of_time
または.enable_percentage_of_actors
を使用します:
# Good: feature needs to be explicitly disabled, as it is enabled by default if not defined
stub_feature_flags(my_feature: false)
stub_feature_flags(my_feature: true)
stub_feature_flags(my_feature: project)
stub_feature_flags(my_feature: [project, project2])
# Bad
Feature.enable(:my_feature_2)
# Good: enable my_feature for 50% of time
Feature.enable_percentage_of_time(:my_feature_3, 50)
# Good: enable my_feature for 50% of actors/gates/things
Feature.enable_percentage_of_actors(:my_feature_4, 50)
定義された状態を持つ各機能フラグは、テスト実行時に永続化されます:
Feature.persisted_names.include?('my_feature') => true
Feature.persisted_names.include?('my_feature_2') => true
Feature.persisted_names.include?('my_feature_3') => true
Feature.persisted_names.include?('my_feature_4') => true
スタビング・アクタ
特定のアクタに対してのみ機能フラグを有効にしたい場合、そのアクタの表現をスタブすることができます。Feature.enabled?
とFeature.disabled?
に引数として渡されるゲートは、FeatureGate
を含むオブジェクトでなければなりません。
仕様では、カスタム・アクタを素早く作成できるstub_feature_flag_gate
メソッドを使用できます:
gate = stub_feature_flag_gate('CustomActor')
stub_feature_flags(ci_live_trace: gate)
Feature.enabled?(:ci_live_trace) # => false
Feature.enabled?(:ci_live_trace, gate) # => true
また、特定のアクタの機能フラグを無効にすることもできます:
gate = stub_feature_flag_gate('CustomActor')
stub_feature_flags(ci_live_trace: false, thing: gate)
テストでの機能フラグエンジンの制御
テスト環境のフリッパーエンジンは、メモリモードFlipper::Adapters::Memory
で動作します。production
とdevelopment
モードでは、Flipper::Adapters::ActiveRecord
を使用します。
Flipper::Adapters::Memory
モードとActiveRecord
モードのどちらを使用するかを制御することができます。
stub_feature_flags: true
(デフォルトと優先)
このモードでは、Flipper はFlipper::Adapters::Memory
を使用するように設定され、すべての機能フラグをオンバイデフォルトとし、初回使用時に永続化します。
機能フラグの動作が、特定のコンテキスト以外ではテストされないようにします。
stub_feature_flags: false
これは、メモリスタブのフリッパーを無効にし、production
とdevelopment
で使用されるモードFlipper::Adapters::ActiveRecord
を使用します。
このモードは、フリッパーとActiveRecord
との相互作用をテストしたい場合にのみ使用してください。
エンドツーエンド(QA) テスト
機能フラグの切り替えは、エンドツーエンド(QA) テストでは動作が異なります。エンドツーエンドのテストフレームワークは Rails やデータベースに直接アクセスできないため、Flipper を使うことができません。代わりに公開 API を使います。各エンドツーエンドテストでは、テスト中に機能フラグを有効/無効にできます。あるいは、GitLab リポジトリのqa
ディレクトリからテストを実行するとき、あるいは](https://gitlab.com/gitlab-org/gitlab/-/tree/master/qa#running-tests-with-a-feature-flag-enabled-or-disabled)GitLab QA 経由でテストを実行](https://gitlab.com/gitlab-org/gitlab/-/tree/master/qa#running-tests-with-a-feature-flag-enabled-or-disabled)するときに、1 つ以上のテストの前に機能フラグを有効/無効にすることもできます。
前述のとおり、機能フラグはエンドツーエンドテストではデフォルトでは有効になりません。つまり、機能フラグを明示的に有効/無効にするようにテストが書かれていない限り、エンドツーエンドのテストは機能フラグがソースコードに実装されているデフォルトの状態、あるいはテスト対象の GitLab インスタンスで機能フラグが現在の状態になっている状態で実行されるということです。
機能フラグがステージやGitLab.com上で変更されると、パイプライントリアージDRIに通知するためにSlackメッセージが#qa-staging
や#qa-production
チャンネルに投稿されます。しかし、もしあなたが変更に取り組んでいるのであれば、機能フラグを有効にした状態でエンドツーエンドのテストがパスすることを確認することで、予期せぬ失敗を避けることができます。
機能フラグによるSidekiqワーカーの動作制御
worker
タイプ の機能フラグを使用して、Sidekiq ワーカーの動作を制御することができます。
Sidekiqジョブの延期
無効にすると、run_sidekiq_jobs_{WorkerName}
の形式の機能フラグは、ジョブを後でスケジューリングすることにより、ワーカーの実行を遅らせます。この機能フラグは、デフォルトではすべてのワーカーで有効になっています。ジョブを遅延させることは、ワーカーインスタンスによる争いの多い動作がインフラリソース (データベースやデータベース接続プールなど) を飽和させているような場合に有効です。実装はSkipJobs Sidekiq サーバミドルウェアにあります。
false に設定すると、100% のジョブが遅延されます。処理を再開させたいときは、時間ロールアウトのパーセンテージを使うことができます。例えば
# not running any jobs, deferring all 100% of the jobs
/chatops run feature set run_sidekiq_jobs_SlowRunningWorker false
# only running 10% of the jobs, deferring 90% of the jobs
/chatops run feature set run_sidekiq_jobs_SlowRunningWorker 10
# running 50% of the jobs, deferring 50% of the jobs
/chatops run feature set run_sidekiq_jobs_SlowRunningWorker 50
# back to running all jobs normally
/chatops run feature delete run_sidekiq_jobs_SlowRunningWorker
Sidekiqジョブの削除
ジョブを延期する代わりに、機能フラグdrop_sidekiq_jobs_{WorkerName}
を有効にすることで、ジョブを完全に削除することができます。この機能フラグを使用するのは、ジョブを削除しても安全であることが確実な場合、つまりジョブを将来処理する必要がない場合です。
# drop all the jobs
/chatops run feature set drop_sidekiq_jobs_SlowRunningWorker true
# process jobs normally
/chatops run feature delete drop_sidekiq_jobs_SlowRunningWorker
drop_sidekiq_jobs_{WorkerName}
run_sidekiq_jobs_{WorkerName}
つまり、drop_sidekiq_jobs
が有効で、drop_sidekiq_jobs_{WorkerName}
が無効の場合、ジョブは完全に削除されます。