Skip to content

Commit d351e55

Browse files
authored
Merge pull request #802 from dahlia/feat/bench/remaining-scenarios
Run remaining benchmark scenarios in `fedify bench`
2 parents 9c39925 + 12bcee9 commit d351e55

48 files changed

Lines changed: 8386 additions & 104 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGES.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,8 +304,22 @@ To be released.
304304
discovery-aware `--dry-run` planning, and ships with a local benchmark
305305
fixture used by the scenario tests. [[#744], [#783], [#784]]
306306

307+
- Added `actor`, `object`, `fanout`, `failure`, and `mixed` scenario runners
308+
to `fedify bench`. Read scenarios can now benchmark actor and object
309+
document fetches, including authenticated GET requests; fanout scenarios
310+
drive the benchmark trigger endpoint and wait for queue task drain; failure
311+
scenarios report expected fault outcomes as successes; and mixed scenarios
312+
run weighted child scenario blends. The `collection` scenario type remains
313+
reserved but not executable. Fanout and remote failure scenarios can set
314+
`sinkBase` to generate deterministic benchmark sink inbox URLs for targets
315+
that keep `triggerSinks` allowlisting enabled. This change is published
316+
as benchmark scenario schema version 2. [[#744], [#785], [#801], [#802]]
317+
307318
[#783]: https://github.com/fedify-dev/fedify/issues/783
308319
[#784]: https://github.com/fedify-dev/fedify/issues/784
320+
[#785]: https://github.com/fedify-dev/fedify/issues/785
321+
[#801]: https://github.com/fedify-dev/fedify/pull/801
322+
[#802]: https://github.com/fedify-dev/fedify/pull/802
309323

310324
### @fedify/fixture
311325

docs/manual/benchmarking.md

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,9 @@ delivery with the same `@fedify/fedify` signer a real peer uses, so the measured
9494
crypto cost is real.
9595

9696
> [!NOTE]
97-
> This version runs the `inbox` and `webfinger` scenario types. The scenario
98-
> format can express the others (`actor`, `object`, `fanout`, `collection`,
99-
> `failure`, and `mixed`), but they are not executed yet. Within the runnable
97+
> This version runs the `inbox`, `webfinger`, `actor`, `object`, `fanout`,
98+
> `failure`, and `mixed` scenario types. The `collection` scenario type is
99+
> reserved by the suite format but is not executed yet. Within the runnable
100100
> types, a few options the format accepts are also not implemented yet and are
101101
> rejected up front with a clear message:
102102
>
@@ -115,7 +115,7 @@ is a superset). The suite declares the `target`, shared `defaults`, the
115115
block of pass/fail thresholds:
116116

117117
~~~~ yaml
118-
# yaml-language-server: $schema=https://json-schema.fedify.dev/bench/scenario-v1.json
118+
# yaml-language-server: $schema=https://json-schema.fedify.dev/bench/scenario-v2.json
119119
version: 1
120120
target: http://localhost:3000
121121
defaults:
@@ -161,7 +161,56 @@ list, deliveries are rotated across the recipients (and across the synthetic
161161
`actors` signing them), modeling a server that receives from many peers into
162162
many local inboxes.
163163

164-
[published schema]: https://json-schema.fedify.dev/bench/scenario-v1.json
164+
[published schema]: https://json-schema.fedify.dev/bench/scenario-v2.json
165+
166+
### Scenario types
167+
168+
The runnable scenario types cover the main benchmark surfaces:
169+
170+
- `inbox`: discovers recipient inboxes and sends signed `Create(Note)`
171+
deliveries through the target's inbound ActivityPub path.
172+
- `webfinger`: drives direct `/.well-known/webfinger` lookups on the target.
173+
- `actor`: resolves actor URLs from the scenario recipients and fetches actor
174+
documents. Set `authenticated: true` to sign those GET requests.
175+
- `object`: fetches object URLs from `source`. Set `authenticated: true` to
176+
sign those GET requests.
177+
- `fanout`: posts to `/.well-known/fedify/bench/trigger` so the target calls
178+
`sendActivity()` and drains its fanout/outbox queue to benchmark-owned sink
179+
inboxes. The command starts those sink inboxes locally. A non-loopback
180+
target therefore needs `--advertise-host` unless the scenario sets
181+
`sinkBase` to a reachable `http://host:port/` URL. The target must either
182+
allow the generated sink inboxes through `triggerSinks` or run with
183+
`allowUnsafeTriggerRecipients` in a controlled benchmark environment. Use
184+
`sinkBase` when you want those inboxes to be deterministic, for example
185+
`http://127.0.0.1:9090/inbox/0` through
186+
`http://127.0.0.1:9090/inbox/4` for `followers: 5`.
187+
`fedify bench` does not switch the target's queue backend; run the same
188+
suite against targets configured with the queue implementations you want to
189+
compare. Fanout triggers are serialized while the runner observes queue
190+
drain, so client latency includes time spent waiting for earlier fanout
191+
drains under high-rate or concurrent load. Use `deliveryThroughput` and
192+
`queueDrain` expectations for delivery performance, and keep request
193+
latency expectations conservative for this scenario type.
194+
- `failure`: records expected fault outcomes as successes. For this
195+
scenario type, `successRate` means “the expected failure was observed,”
196+
not “the HTTP request succeeded.” The `invalid-signature` and
197+
`missing-actor` faults send malformed signed deliveries to a recipient
198+
inbox. The `remote-404`, `remote-410`, `slow-inbox`, and `network-error`
199+
faults post to the benchmark trigger endpoint with `sender`, so the target
200+
uses its normal outbound delivery path against controlled benchmark-owned
201+
sink inboxes. Like `fanout`, these remote failure faults need
202+
`--advertise-host` for a non-loopback target unless `sinkBase` gives a
203+
reachable, fixed sink base URL that the target's `triggerSinks` can
204+
preconfigure. Remote failure deliveries are also serialized while the
205+
runner waits for the target's queue to
206+
observe the expected failure or retry signal, so request latency can include
207+
earlier wait time when the configured load is concurrent or high-rate.
208+
- `mixed`: runs referenced child scenarios concurrently, splitting the
209+
`mixed` scenario's load by each entry's `weight`. The referenced
210+
scenarios are named scenarios in the same suite and are still run as normal
211+
suite entries when listed. The mixed result merges client-side request,
212+
throughput, delivery throughput, latency, and error measurements;
213+
server-side metric snapshots are not merged across child runners.
165214

166215
### Actors
167216

@@ -239,7 +288,7 @@ CI check. Keep CI gates on robust signals such as success rate, error counts,
239288
and gross throughput or latency floors; precise latency-percentile regression
240289
belongs in a controlled environment, not a shared CI runner.
241290

242-
[report schema]: https://json-schema.fedify.dev/bench/report-v1.json
291+
[report schema]: https://json-schema.fedify.dev/bench/report-v2.json
243292

244293
### Safety
245294

@@ -347,6 +396,11 @@ allowlist. To bypass this guard for a controlled run, set
347396
`~FederationBenchmarkOptions.allowUnsafeTriggerRecipients` to `true` in the
348397
application configuration.
349398

399+
For `fanout` and remote `failure` scenarios, set a `sinkBase` value such as
400+
`http://host:port/` in the scenario when the target keeps the safe default and
401+
you need stable sink URLs for `triggerSinks`. With `followers: 5`, the runner
402+
generates `/inbox/0` through `/inbox/4` under that base.
403+
350404
A successful trigger returns `202 Accepted`:
351405

352406
~~~~ json

packages/cli/src/bench/__fixtures__/invalid/failure-missing-fault.yaml

Lines changed: 0 additions & 6 deletions
This file was deleted.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Server-side metrics are not merged for mixed scenario results.
2+
version: 1
3+
target: http://localhost:3000
4+
scenarios:
5+
- name: realistic-blend
6+
type: mixed
7+
mix:
8+
- { scenario: fanout-1k, weight: 1 }
9+
expect:
10+
queueDrain.p95: "< 2s"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# signatureVerification.* is only valid for authenticated object scenarios.
2+
version: 1
3+
target: http://localhost:3000
4+
scenarios:
5+
- name: object-fetch
6+
type: object
7+
source: http://localhost:3000/objects/1
8+
expect:
9+
signatureVerification.p95: "< 10ms"

packages/cli/src/bench/__fixtures__/reports/inbox-report.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"$schema": "https://json-schema.fedify.dev/bench/report-v1.json",
3-
"schemaVersion": 1,
2+
"$schema": "https://json-schema.fedify.dev/bench/report-v2.json",
3+
"schemaVersion": 2,
44
"tool": { "name": "@fedify/cli", "version": "2.3.0" },
55
"environment": {
66
"runtime": "deno",

packages/cli/src/bench/__fixtures__/scenarios/all-types.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# yaml-language-server: $schema=https://json-schema.fedify.dev/bench/scenario-v1.json
2-
# Exercises every scenario type the format can express, even though only
3-
# `inbox` and `webfinger` have runners in this version.
2+
# Exercises every scenario type the format can express; `collection` is still
3+
# reserved but not executable in this version.
44
version: 1
55
target: http://localhost:3000
66
defaults:
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# yaml-language-server: $schema=https://json-schema.fedify.dev/bench/scenario-v2.json
2+
version: 1
3+
target: http://localhost:3000
4+
scenarios:
5+
- name: signed-object-fetch
6+
type: object
7+
authenticated: true
8+
source: http://localhost:3000/objects/1
9+
expect:
10+
signatureVerification.p95: "< 10ms"

0 commit comments

Comments
 (0)