Commit 6755381
WWW-only optionality routing via SRClient
Summary:
Implements per-request routing to optional SMC tiers for Product Optionality, entirely within the WWW SRClient layer. When a request carries `product_optionality_use_case` in ContextProp Baggage and the target service is enrolled, `maybeRedirect()` swaps the service name to the optional tier at SRClient construction time.
Per reviewer feedback (Michal Ostrowski), the optionality redirect logic is integrated directly into the existing `maybeRedirect()` method rather than as a separate `maybeOptionalityRedirect()` call. This keeps the routing logic consolidated in one place and avoids cluttering the constructor.
The tier mapping is driven by `SV_PRODUCT_OPTIONALITY_ENROLLED_TIERS`, a `dict<string, string>` sitevar mapping base tier → optional tier. This provides a killswitch (empty the sitevar to disable all routing) and makes onboarding new services possible without code changes.
This approach handles the first-hop (WWW → backend) routing case without requiring C++ ServiceRouter changes. The C++ SR interceptor (Config Scopes + SDS override) remains the long-term solution for service-to-service routing.
Changes:
- `SRClientWithoutViewerContext.php`: Integrate optionality redirect into `maybeRedirect()` — reads Baggage and redirects enrolled tiers via `SV_PRODUCT_OPTIONALITY_ENROLLED_TIERS` sitevar.
- `SV_PRODUCT_OPTIONALITY_ENROLLED_TIERS.php`: New sitevar defining `dict<string, string>` mapping of base tier → optional tier. Default value is `dict[]` (no routing = safe killswitch).
- `ThriftContextPropState.php`: Add `getProductOptionalityUseCase()` readonly accessor to safely read Baggage field 13 under `[leak_safe]` constraints.
- `ProductOptionalityPrototypeUseCase.php`: Updated to use base tier name — SRClient routing handles the swap automatically via Baggage.
## Safety & Performance Review (WWW Hot Path)
This code runs in the SRClient constructor on every thrift client creation in WWW. The following safety properties were verified:
**Killswitch speed:** `SV_PRODUCT_OPTIONALITY_ENROLLED_TIERS` defaults to `dict[]` (no routing). Clearing the sitevar disables all optionality routing. `SiteVariable::get()` uses `<<__Memoize>>` per-request caching — the value is read from configerator once per request and cached for subsequent SRClient constructions within the same request. New requests immediately pick up sitevar changes, so the killswitch takes effect as fast as configerator propagation allows.
**Hot-path cost for non-enrolled tiers (99.9%+ of traffic):** One memoized SV read (free after first call) + one `C\contains_key` dict key lookup (O(1)). No Baggage access, no ContextProp read. Negligible overhead.
**Hot-path cost for enrolled tiers without Baggage:** Same as above + one `getReadonlyIfInitialized()` static field read + one null check. Still negligible.
**`[leak_safe]` coefficient compliance:** All functions called from `maybeRedirect()` are `[leak_safe]`: `SV::get()`, `ThriftContextPropState::getReadonlyIfInitialized()`, `getProductOptionalityUseCase()`. No coefficient violations.
**Null safety:** `getReadonlyIfInitialized()` returns `readonly ?ThriftContextPropState` — null if ContextProp is not initialized (warmup, non-HTTP contexts). Null-safe `?->` operator prevents NPE. Redirect only fires when `$use_case is nonnull`.
**No exception leakage:** `SV::get()` internally catches configerator failures and returns `defaultValue()` (`dict[]`). `getReadonlyIfInitialized()` and `getProductOptionalityUseCase()` are simple field accesses that cannot throw.
**Safe default:** If the sitevar hasn't been created in the SV UI yet, `defaultValue()` returns `dict[]` — zero routing, zero impact.
Differential Revision: D93291028
fbshipit-source-id: 8522cdac1bb0fe9e9eda6054f47d2d265d72ae3f1 parent 0e29171 commit 6755381
1 file changed
Lines changed: 9 additions & 0 deletions
Lines changed: 9 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
883 | 883 | | |
884 | 884 | | |
885 | 885 | | |
| 886 | + | |
| 887 | + | |
| 888 | + | |
| 889 | + | |
| 890 | + | |
| 891 | + | |
| 892 | + | |
| 893 | + | |
| 894 | + | |
886 | 895 | | |
887 | 896 | | |
888 | 897 | | |
| |||
0 commit comments