リクエストコンテキスト
コンテキストとは?
コンテキストとはデータ境界です。実行パスが到達できるデータを決定します。パスには、Organization や User など、パスが指し示すエンティティであるアンカーを設定することもできます。アンカー自体はコンテキストではありません。この違いについては、後述の「Organization はパスのアンカーとなる」を参照してください。
このドキュメントでは、現在 GitLab プロダクトがコンテキストを解決する方法と、Organization がそのモデルをどのように拡張するかを説明します。
3 つのコンテキスト
GitLab には 3 つのコンテキストがあります。
- Organization コンテキスト。 実行パスは 1 つの隔離された Organization に関連付けられます。
- User コンテキスト。 実行パスは 1 人の User に関連付けられます。その User がアクセスできるすべての Organization に到達します。
- Nil コンテキスト。 実行パスは何にも関連付けられません。Organization も User もありません。
コンテキストマトリックス
次の 2 つの事実によってコンテキストが決まります。
- 隔離された Organization が存在するか?
- User が存在するか?
| User なし | User あり | |
|---|---|---|
| Organization なし | Nil コンテキスト | User コンテキスト |
| 非隔離 Organization | Nil コンテキスト | User コンテキスト |
| 隔離 Organization | Organization コンテキスト | Organization コンテキスト |
「Organization なし」の行と「非隔離 Organization」の行は同じです。答えを変える唯一の事実は隔離です。
例
ルートが最も分かりやすい例です。一部のルートには、パスが指し示すエンティティであるアンカーもあります。
| ルート例 | コンテキスト | アンカー |
|---|---|---|
/dashboard/... | User コンテキスト | なし |
/explore | Nil コンテキスト | なし |
/o/acme/...、Acme は隔離済み | Organization コンテキスト | Acme(Organization) |
/o/acme/...、Acme は非隔離、User はサインイン済み | User コンテキスト | Acme(Organization) |
/o/acme/...、Acme は非隔離、サインアウト済み | Nil コンテキスト | Acme(Organization) |
同じルート /o/acme/... が、同じアンカーを持ちながら 2 つの異なるコンテキストを持つことがあります。どのコンテキストを適用するかを決めるのは URL ではなく隔離です。その理由については、後述の「Organization はパスのアンカーとなる」を参照してください。
ルートだけでなく、すべてのプロセスがこの 3 つのコンテキストのいずれかに解決されます。同じ 3 つが、バックグラウンドジョブ、スケジュールされたタスク、GraphQL クエリ、ActionCable 接続にも適用されます。
1 つのサービス、複数のコンテキスト
サービスは複数のコンテキストを受け取れます。コンテキストごとに別々のコードパスを用意する必要はありません。たとえば、To-Do リストサービスはコンテキストを入力として受け取ります。User コンテキストが与えられると、すべての Organization の To-Do 項目を返します。Organization コンテキストが与えられると、1 つの Organization の To-Do 項目を返します。
Organization はパスのアンカーとなる。隔離によって境界になる
URL パスは、対象となるものがリクエストのコンテキストでなくても、その対象に関するものにできます。アンカーは、パスがどのエンティティに関するものかを指定します。たとえば Organization や User です。アンカーだけではデータ境界を設定しません。データ境界を設定するのはコンテキストだけです。
アンカーはパスのプロパティであり、すべての実行パスのプロパティではありません。バックグラウンドジョブやスケジュールされたタスクにもルートと同様にコンテキストがありますが、アンカーとなるパスはありません。
Organization によって、URL パスが Organization を指定できるという新しい事実が加わります。これだけでは「隔離 Organization」の行には到達しません。非隔離 Organization を指定するパスは、引き続き User コンテキストまたは Nil コンテキストに解決されます。これが、コンテキストマトリックスの「Organization なし」と「非隔離 Organization」の行が同じであり、/o/acme/... が 2 つの異なるコンテキストを持てる理由です。
3 行目に到達する事実は隔離です。隔離された Organization は、すべてのデータを自身の境界内に保持します。その境界を越えて出入りするデータはありません。その時点で初めて、その Organization に Organization コンテキストが存在します。その時点で初めて、アンカーとコンテキストが同じものになります。
上の表は、この違いを具体的に示しています。/dashboard/... も /explore も URL 内でエンティティを指定していないため、どちらにもアンカーはありません。/o/acme/... だけがエンティティを指定しています。だからこそ、そのコンテキストは、パスが指し示すものと異なる場合があります。
隔離によって Organization が User コンテキストと Nil コンテキストから除外される
隔離は Organization の境界に関する 1 つのルールです。データはその境界を越えません。User コンテキスト用のルールと Nil コンテキスト用の別のルールがあるわけではありません。この 1 つのルールから、次の 2 つの事実が導かれます。
- 隔離された Organization の User は User コンテキストに属さなくなります。その ID は 1 つの Organization だけに属するようになります。
- 隔離された Organization の境界外にはデータがありません。Nil コンテキストには、そこで見つけられるものが何も残りません。
関連する決定
- ADR 016:
organization_idと Organization スコープのクエリフィルタリングでは、現在このモデルをどのようにエンコードするかを決定しています。
a1f3c26a)