Skip to content

Tags: meta/fbthrift

Tags

v2026.10.26.00

Toggle v2026.10.26.00's commit message
Write binary map keys as base64 when they are member names

Summary:
## Context
With `mapPrimitiveKeysAsMemberNames` on and `binaryAsBase64String` off, [[ https://www.internalfb.com/code/fbsource/fbcode/thrift/lib/cpp2/protocol/detail/Json5ProtocolWriter.cpp?lines=334-356 | Json5ProtocolWriter::writeBinary ]] wrote a binary map key as its raw bytes in the member name. [[ https://www.internalfb.com/code/fbsource/fbcode/thrift/lib/cpp2/protocol/detail/Json5ProtocolReader.cpp?lines=465-469 | Json5ProtocolReader::readBinaryValue ]] always decodes a member-name binary key as base64, so the writer's output did not read back.

## Behavior change
Options: `mapPrimitiveKeysAsMemberNames` on, `binaryAsBase64String` off.

**Now round-trips (silently corrupted before)**

| Input | Field type | Before | After |
| --- | --- | --- | --- |
| `binaryAsKey = {"abcd": 1}` | `map<binary, i32>` | written as `{"binaryAsKey":{"abcd":1}}`, read back with key <69 B7 1D> | written as `{"binaryAsKey":{"YWJjZA":1}}`, read back with key `abcd` |

**Now round-trips (failed before)**

| Input | Field type | Before | After |
| --- | --- | --- | --- |
| `binaryAsKey = {"?~": 1}` | `map<binary, i32>` | written as `{"binaryAsKey":{"?~":1}}`, read rejected (not base64) | written as `{"binaryAsKey":{"P34":1}}`, read back with key `?~` |
| `binaryAsKey = {<FF>: 1}` | `map<binary, i32>` | write rejected (not UTF-8) | written as `{"binaryAsKey":{"/w":1}}`, read back with key <FF> |

**Unchanged**

| Input | Options | Before | After |
| --- | --- | --- | --- |
| `binaryAsKey = {"?~": 1}` | `mapPrimitiveKeysAsMemberNames` and `binaryAsBase64String` on | `{"binaryAsKey":{"P34":1}}` | `{"binaryAsKey":{"P34":1}}` |
| `binaryAsKey = {"?~": 1}` | defaults | `{"binaryAsKey":[{"key":{"utf-8":"?~"},"value":1}]}` | `{"binaryAsKey":[{"key":{"utf-8":"?~"},"value":1}]}` |
| `binaryValue = "?~"` | `mapPrimitiveKeysAsMemberNames` on | `{"binaryValue":{"utf-8":"?~"}}` | `{"binaryValue":{"utf-8":"?~"}}` |

Every caller found in fbsource that enables `mapPrimitiveKeysAsMemberNames` also sets `binaryAsBase64String`, so their output does not change.

## In this Diff
`writeBinary` now uses unpadded base64, the encoding `binaryAsBase64String` already uses, for any binary written as an object member name. A member name cannot hold the `{"utf-8": ...}` form that tells the reader how a binary value is encoded, so base64 is the only form the reader can decode there.

___

landed-with-radar-review

Differential Revision: D127514962

fbshipit-source-id: 91fab09964ec146f230b6ab3cb65004091e40330

v2026.10.19.00

Toggle v2026.10.19.00's commit message
Attribute stream flow-control wait time

Summary:
# Summary

**TL;DR:** Attribute Thrift stream flow-control waits to the wall-time profiler and expose their duration in per-service Thrift dynostats.

**Rule:** Low-level async I/O waits must end their `WallTimeOperation` and record the resulting I/O duration in the corresponding profiling counter.

 ---

## Context

`ThriftProcessorBase::genStream` waits for client stream credits through `$server_stream->genIsStreamReady()`. Without a `WallTimeOperation`, the wall-time profiler cannot attribute that external-thread-event wait and reports `UnattributedIOTimeException`.

This surfaced when Nest GraphQL-over-Thrift streaming traffic increased, producing roughly 20k profiling-completeness violations per day.

- Task: T290256140
- MID: [opes/6ad7eca509ccfc81c34edbbc345195bc](http://www.internalfb.com/logview/opes/6ad7eca509ccfc81c34edbbc345195bc)

## This diff

- Wrap the `genIsStreamReady()` await in a `WallTimeOperation` with `try`/`finally` so the operation always ends, including cancellation and exception paths.
- Record the wait as `ProfilingCounterDuration::THRIFT_READ_DURATION` using `getOldestRunningIODuration()`.
- Attribute the dynostats duration to `static::THRIFT_SVC_NAME` for per-service visibility.

Reviewed By: jano

Differential Revision: D122232086

fbshipit-source-id: 5ef07ce26a7706846999609ccd1011d4fb1b62f4

v2026.10.12.00

Toggle v2026.10.12.00's commit message
Propagate explicitly tagged Bronze/Sheddable RequestPriority to allow…

…listed downstreams

Summary:
Adds `RequestPriorityContextHandler`, a ContextProp V2 `IContextHandler` that writes www's effective request priority onto the outgoing `ThriftFrameworkMetadata.request_priority` for allowlisted downstream services. Multifeed aggregator tiers are the first target.

Behavior in `onOutgoingDownstream()`:
- Effective priority = `MCPContext::getRequestPriority()`: AdmissionControl's resolved priority, the same value used for throttling. Every tagger (PrivacyLib, OUC tiers, Falco, GraphQL2, FAM ads) goes through `AdmissionControl::genCheck` and stores the admitted priority in implicit context, scoped to that request or function call tree, so concurrent branches outside an OUC scope are unaffected. Deliberately not read: the request-global `ThriftContextPropState` (S715712 leak source) and `PrivacyLibRequestPriorityState` (request-global and last-writer-wins across concurrent PrivacyLib executions, so code outside any IC scope could pick up another branch's Bronze). Code outside IC scope sends NULL.
- Only `SHEDDABLE_PLUS` (Bronze) and `SHEDDABLE` are ever written. Untagged traffic and `CRITICAL`/`CRITICAL_PLUS` keep sending a null priority. This avoids the S640167 failure mode (see D98537289), where writing the default `CRITICAL` for all traffic activated dormant downgrade logic downstream.
- Gated by the existing JK `www/web_efficiency_infra:pl_set_priority_to_tcp`, evaluated with switchval = SR `service_name` (per-destination allowlist; default false) and hashval = request id (% ramp). This knob originally gated the removed PrivacyLib TCP setter and has no other readers.
- Never upgrades: if the TFM already carries a more sheddable upstream priority, that value is kept.
- Only mutates the per-call TFM copy built by `TContextPropV2ClientHandler`. The global `ThriftContextPropState` is untouched, so in-process readers (MAPI/AM priority handlers, ADAL, Galileo request utils) see no change, and concurrent calls cannot inherit a scoped priority (S715712). Per-client floors such as `IGAdsDjangoCallCriticalPriorityContextHandler` (D123515309) are attached after this handler and still win.

Registered in `ThriftContextPropHandlers::install()` next to `ProductIdContextHandler`, behind the killswitch `upop/contextprop_priority:disable_request_priority_context_handler` (default false). That covers every SR Thrift client: `servicerouter/thrift_context_prop:enabled` is fully on.

Context: "ContextProp: From Web to Downstream" doc (https://docs.google.com/document/d/1PJWKXE8MxarX09WMH621kDojLkmJSQguN1arXcskpxo).

Reviewed By: DavidLouie

Differential Revision: D123739942

fbshipit-source-id: 4234e8443b715184d39fc86ead75fa63dc0962cd

v2026.10.05.00

Toggle v2026.10.05.00's commit message
Update recommended HTTP headers

Summary:
Updates the generated common-header files.

Diff resulted from pipeline (D115638777) and is first in plan to generate a monthly bot to update the common headers lists. Diff consists of updates to the headers list files, and resulting build errors from callers of it.

In HTTPCommonHeaders.txt: Added 4 headers, removed 16

In FacebookHTTPHeaders.txt: Added 63 Headers, removed 51

The net total between the two lists stayed as 254 headers.
For details on the decision of how headers were chosen to be removed this diff explains (D115508426), but tldr is:

- Headers counts were aggregated (1/10^6 sampling) to a scuba table
- Through the actual count of each header itself, the tiers each header appearance occurred on (slightly more value for edge and fna tiers), and the amount a header enum appears in code (for listed headers), a score was assigned to each header (higher score -> more valuable)
- The scores were sorted such that if [highest scored non-list header / lowest scored listed header] was greater than a certain ratio (chose 2.0 for first run), the header would replace it on the list
- This kept going until all of the non-listed headers were checked with the lowest scored non-swapped listed headers

Additionally: Theres a DENY_LIST for headers that likely shouldn't be removed (some psuedoheaders, connection headers, etc...) and for headers used more than 50 times in code as I deemed that traffic over a few weeks period of time likely isn't enough to justify removing them.

If you believe that a header was removed that you don't think should be removed from the list or if you believe anything gets broken from this change please lmk.

But advantages of this change can be seen below in the test plan when testing on different canary teirs.

Reviewed By: hanidamlaj

Differential Revision: D116961031

fbshipit-source-id: 9d6c281ba22ed3732fddb3f860527deb20f756fa

v2026.09.28.00

Toggle v2026.09.28.00's commit message
Move instead of copy message temporary in TLibraryException constructor

Reviewed By: cnli87

Differential Revision: D122056416

fbshipit-source-id: 7258dfdfe6f32caf1441ede59350bc2d625931ae

v2026.09.21.00

Toggle v2026.09.21.00's commit message
Revert D120720989: Keep TStructDataStorage members out of writable .r…

…odata

Differential Revision:
D120720989

Original commit changeset: 4fbbf6c47a56

Original Phabricator Diff: D120720989

fbshipit-source-id: 65c5292a840dc474da280c93fc9c4671a50b2ae1

v2026.09.07.00

Toggle v2026.09.07.00's commit message
Expose the application adapter factory

Summary:
Expose the application adapter factory registered with `FastThriftServer`, mirroring classic `ThriftServer::getProcessorFactory()`. This lets pre-start integrations consume the generated service metadata and schema without including auxiliary interfaces or enabling the wire metadata service.

___

Differential Revision: D119040039

fbshipit-source-id: 2261ee4a6692ebe435d29c9a75d41638a6c93044

v2026.08.31.00

Toggle v2026.08.31.00's commit message
Deprecate ChainInterceptors

Summary: Mark ChainInterceptors as deprecated and direct callers to the modern ServiceInterceptor API.

Reviewed By: adolfojunior

Differential Revision: D117902588

fbshipit-source-id: 18f569dc1f02deacf7c924c56901ef8b2944d0f9

v2026.08.24.00

Toggle v2026.08.24.00's commit message
Carry the per-connection and per-request internal fields

Summary: Gives `ThriftConnContext` and `ThriftRequestContext` the `getInternalFields<T>()` slot the classic contexts carry, over fast_thrift's own `TypeErasedValue<128>` and pluggable functions rather than a dependency on `Cpp2ConnContext`.

Reviewed By: robertroeser

Differential Revision: D116839752

fbshipit-source-id: e7f5da7ae639c2b7a3e20c8b275adc18e323820c