Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
d341039
Add read benchmark scenarios
dahlia Jun 9, 2026
ec9667f
Add fanout benchmark scenario
dahlia Jun 9, 2026
f80970c
Add failure and mixed scenarios
dahlia Jun 9, 2026
77fa941
Document benchmark scenario coverage
dahlia Jun 9, 2026
91493e7
Fix benchmark scenario preflight gates
dahlia Jun 9, 2026
0a8929b
Fix benchmark measurement safeguards
dahlia Jun 9, 2026
7ed3108
Preserve mixed benchmark safety caps
dahlia Jun 9, 2026
08d7bbd
Gate object dry-run discovery safely
dahlia Jun 9, 2026
f867e34
Reuse dry-run fetch for actor discovery
dahlia Jun 9, 2026
61a43c9
Keep read and failure measurements focused
dahlia Jun 9, 2026
207bb87
Fix fanout and failure gates
dahlia Jun 9, 2026
682c635
Separate actorless and delivery gates
dahlia Jun 9, 2026
3af3e35
Keep fanout request throughput separate
dahlia Jun 9, 2026
80e0ba3
Preserve fanout delivery reports
dahlia Jun 9, 2026
67ec733
Preserve failure and mixed correctness
dahlia Jun 9, 2026
e11e216
Drive failure faults through targets
dahlia Jun 10, 2026
5678ea9
Tighten actor and object discovery
dahlia Jun 10, 2026
fd026c0
Reject mixed server metric gates
dahlia Jun 10, 2026
17bdbe5
Reject invalid read destinations
dahlia Jun 10, 2026
fc1390f
Reject ambiguous benchmark preflight configs
dahlia Jun 10, 2026
5c40332
Observe network-error retry scheduling
dahlia Jun 10, 2026
925289c
Keep failed fanout metrics honest
dahlia Jun 10, 2026
0a1afeb
Settle mixed runs before reporting errors
dahlia Jun 11, 2026
f082407
Update benchmark scenario help text
dahlia Jun 11, 2026
e57cc84
Make failure discovery test deterministic
dahlia Jun 11, 2026
9aeff9d
Resolve relative object discovery links
dahlia Jun 11, 2026
5c40e2b
Document serialized benchmark wait latency
dahlia Jun 11, 2026
63ad3c5
Tighten benchmark helper documentation
dahlia Jun 11, 2026
fa3ebf2
Tolerate transient stats polling failures
dahlia Jun 11, 2026
01921df
Cap object source collection crawls
dahlia Jun 11, 2026
2668a9e
Guard mixed limiter releases
dahlia Jun 11, 2026
90f9a33
Follow Link hrefs during object discovery
dahlia Jun 11, 2026
b2dfcf8
Make benchmark sink URLs configurable
dahlia Jun 11, 2026
f8ad54a
Skip malformed discovered object URLs
dahlia Jun 11, 2026
222f34f
Corrupt failure signatures directly
dahlia Jun 11, 2026
7bbff1c
Publish benchmark scenario schema v2
dahlia Jun 11, 2026
eca9e54
Continue after bad object candidates
dahlia Jun 11, 2026
d7c4d74
Share failure sinks for fault mixes
dahlia Jun 11, 2026
dfaee9b
Drain failed discovery responses
dahlia Jun 11, 2026
1c2cd49
Require queue work before fanout drain
dahlia Jun 11, 2026
c747792
Parallelize read destination gates
dahlia Jun 11, 2026
b4d4b45
Ignore invalid sink latency values
dahlia Jun 11, 2026
83b85b1
Guard authenticated read actor keys
dahlia Jun 11, 2026
035c5a5
Clarify object discovery JSON errors
dahlia Jun 11, 2026
39908e5
Ignore malformed stats sum points
dahlia Jun 11, 2026
77de059
Default failure reachability checks
dahlia Jun 11, 2026
92c310d
Gate mixed children as children
dahlia Jun 11, 2026
2a82357
Limit read destination gate fanout
dahlia Jun 11, 2026
c231665
Skip wrapper activities without objects
dahlia Jun 11, 2026
4241614
Allow signed object metric gates
dahlia Jun 11, 2026
36dd105
Align mixed expectation schema
dahlia Jun 12, 2026
93bf174
Unwrap nested object activities
dahlia Jun 12, 2026
d98e09b
Respect baseline queue backlog
dahlia Jun 12, 2026
4ee6ba0
Gate benchmark sink recipients
dahlia Jun 12, 2026
4830f15
Tighten failure benchmark checks
dahlia Jun 12, 2026
c88845c
Handle typed object references
dahlia Jun 12, 2026
3760574
Tighten read benchmark preflight
dahlia Jun 12, 2026
73cf1c1
Settle benchmark discovery workers
dahlia Jun 12, 2026
027462d
Limit fetched object reference depth
dahlia Jun 12, 2026
1d3e9ce
Preserve invalid signature grammar
dahlia Jun 12, 2026
12bcee9
Honor fanout follower schema minimum
dahlia Jun 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,22 @@ To be released.
discovery-aware `--dry-run` planning, and ships with a local benchmark
fixture used by the scenario tests. [[#744], [#783], [#784]]

- Added `actor`, `object`, `fanout`, `failure`, and `mixed` scenario runners
to `fedify bench`. Read scenarios can now benchmark actor and object
document fetches, including authenticated GET requests; fanout scenarios
drive the benchmark trigger endpoint and wait for queue task drain; failure
scenarios report expected fault outcomes as successes; and mixed scenarios
run weighted child scenario blends. The `collection` scenario type remains
reserved but not executable. Fanout and remote failure scenarios can set
`sinkBase` to generate deterministic benchmark sink inbox URLs for targets
that keep `triggerSinks` allowlisting enabled. This change is published
as benchmark scenario schema version 2. [[#744], [#785], [#801], [#802]]

[#783]: https://github.com/fedify-dev/fedify/issues/783
[#784]: https://github.com/fedify-dev/fedify/issues/784
[#785]: https://github.com/fedify-dev/fedify/issues/785
[#801]: https://github.com/fedify-dev/fedify/pull/801
[#802]: https://github.com/fedify-dev/fedify/pull/802

### @fedify/fixture

Expand Down
66 changes: 60 additions & 6 deletions docs/manual/benchmarking.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,9 @@ delivery with the same `@fedify/fedify` signer a real peer uses, so the measured
crypto cost is real.

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

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

[published schema]: https://json-schema.fedify.dev/bench/scenario-v1.json
[published schema]: https://json-schema.fedify.dev/bench/scenario-v2.json

### Scenario types

The runnable scenario types cover the main benchmark surfaces:

- `inbox`: discovers recipient inboxes and sends signed `Create(Note)`
deliveries through the target's inbound ActivityPub path.
- `webfinger`: drives direct `/.well-known/webfinger` lookups on the target.
- `actor`: resolves actor URLs from the scenario recipients and fetches actor
documents. Set `authenticated: true` to sign those GET requests.
- `object`: fetches object URLs from `source`. Set `authenticated: true` to
sign those GET requests.
- `fanout`: posts to `/.well-known/fedify/bench/trigger` so the target calls
`sendActivity()` and drains its fanout/outbox queue to benchmark-owned sink
inboxes. The command starts those sink inboxes locally. A non-loopback
target therefore needs `--advertise-host` unless the scenario sets
`sinkBase` to a reachable `http://host:port/` URL. The target must either
allow the generated sink inboxes through `triggerSinks` or run with
`allowUnsafeTriggerRecipients` in a controlled benchmark environment. Use
`sinkBase` when you want those inboxes to be deterministic, for example
`http://127.0.0.1:9090/inbox/0` through
`http://127.0.0.1:9090/inbox/4` for `followers: 5`.
`fedify bench` does not switch the target's queue backend; run the same
suite against targets configured with the queue implementations you want to
compare. Fanout triggers are serialized while the runner observes queue
drain, so client latency includes time spent waiting for earlier fanout
drains under high-rate or concurrent load. Use `deliveryThroughput` and
`queueDrain` expectations for delivery performance, and keep request
latency expectations conservative for this scenario type.
- `failure`: records expected fault outcomes as successes. For this
scenario type, `successRate` means “the expected failure was observed,”
not “the HTTP request succeeded.” The `invalid-signature` and
`missing-actor` faults send malformed signed deliveries to a recipient
inbox. The `remote-404`, `remote-410`, `slow-inbox`, and `network-error`
faults post to the benchmark trigger endpoint with `sender`, so the target
uses its normal outbound delivery path against controlled benchmark-owned
sink inboxes. Like `fanout`, these remote failure faults need
`--advertise-host` for a non-loopback target unless `sinkBase` gives a
reachable, fixed sink base URL that the target's `triggerSinks` can
preconfigure. Remote failure deliveries are also serialized while the
runner waits for the target's queue to
observe the expected failure or retry signal, so request latency can include
earlier wait time when the configured load is concurrent or high-rate.
- `mixed`: runs referenced child scenarios concurrently, splitting the
`mixed` scenario's load by each entry's `weight`. The referenced
scenarios are named scenarios in the same suite and are still run as normal
suite entries when listed. The mixed result merges client-side request,
throughput, delivery throughput, latency, and error measurements;
server-side metric snapshots are not merged across child runners.

### Actors

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

[report schema]: https://json-schema.fedify.dev/bench/report-v1.json
[report schema]: https://json-schema.fedify.dev/bench/report-v2.json

### Safety

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

For `fanout` and remote `failure` scenarios, set a `sinkBase` value such as
`http://host:port/` in the scenario when the target keeps the safe default and
you need stable sink URLs for `triggerSinks`. With `followers: 5`, the runner
generates `/inbox/0` through `/inbox/4` under that base.

A successful trigger returns `202 Accepted`:

~~~~ json
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Server-side metrics are not merged for mixed scenario results.
version: 1
target: http://localhost:3000
scenarios:
- name: realistic-blend
type: mixed
mix:
- { scenario: fanout-1k, weight: 1 }
expect:
queueDrain.p95: "< 2s"
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# signatureVerification.* is only valid for authenticated object scenarios.
version: 1
target: http://localhost:3000
scenarios:
- name: object-fetch
type: object
source: http://localhost:3000/objects/1
expect:
signatureVerification.p95: "< 10ms"
4 changes: 2 additions & 2 deletions packages/cli/src/bench/__fixtures__/reports/inbox-report.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.fedify.dev/bench/report-v1.json",
"schemaVersion": 1,
"$schema": "https://json-schema.fedify.dev/bench/report-v2.json",
"schemaVersion": 2,
"tool": { "name": "@fedify/cli", "version": "2.3.0" },
"environment": {
"runtime": "deno",
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/bench/__fixtures__/scenarios/all-types.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# yaml-language-server: $schema=https://json-schema.fedify.dev/bench/scenario-v1.json
# Exercises every scenario type the format can express, even though only
# `inbox` and `webfinger` have runners in this version.
# Exercises every scenario type the format can express; `collection` is still
# reserved but not executable in this version.
version: 1
target: http://localhost:3000
defaults:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# yaml-language-server: $schema=https://json-schema.fedify.dev/bench/scenario-v2.json
version: 1
target: http://localhost:3000
scenarios:
- name: signed-object-fetch
type: object
authenticated: true
source: http://localhost:3000/objects/1
expect:
signatureVerification.p95: "< 10ms"
Loading
Loading