@rikalabs/akter 0.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/LICENSE +202 -0
- package/NOTICE +8 -0
- package/README.md +116 -0
- package/dist/actor/codecs.d.ts +77 -0
- package/dist/actor/codecs.js +87 -0
- package/dist/actor/connections.d.ts +34 -0
- package/dist/actor/connections.js +145 -0
- package/dist/actor/definition.d.ts +893 -0
- package/dist/actor/definition.js +147 -0
- package/dist/actor/descriptor.d.ts +172 -0
- package/dist/actor/descriptor.js +367 -0
- package/dist/actor/handles.d.ts +77 -0
- package/dist/actor/handles.js +265 -0
- package/dist/actor/jobs.d.ts +10 -0
- package/dist/actor/jobs.js +137 -0
- package/dist/actor/layers.d.ts +41 -0
- package/dist/actor/layers.js +177 -0
- package/dist/actor/reads.d.ts +47 -0
- package/dist/actor/reads.js +224 -0
- package/dist/actor/served.d.ts +120 -0
- package/dist/actor/served.js +72 -0
- package/dist/actor/turns.d.ts +13 -0
- package/dist/actor/turns.js +332 -0
- package/dist/actor/workflows.d.ts +16 -0
- package/dist/actor/workflows.js +37 -0
- package/dist/client/calls.d.ts +47 -0
- package/dist/client/calls.js +425 -0
- package/dist/client/clock.d.ts +56 -0
- package/dist/client/clock.js +119 -0
- package/dist/client/fleet-page.d.ts +15 -0
- package/dist/client/fleet-page.js +13 -0
- package/dist/client/fleet.d.ts +29 -0
- package/dist/client/fleet.js +51 -0
- package/dist/client/index.d.ts +17 -0
- package/dist/client/index.js +6 -0
- package/dist/client/make.d.ts +157 -0
- package/dist/client/make.js +221 -0
- package/dist/client/offline/queue.d.ts +118 -0
- package/dist/client/offline/queue.js +292 -0
- package/dist/client/offline/store.d.ts +74 -0
- package/dist/client/offline/store.js +78 -0
- package/dist/client/optimistic.d.ts +57 -0
- package/dist/client/optimistic.js +136 -0
- package/dist/client/report.d.ts +2 -0
- package/dist/client/report.js +8 -0
- package/dist/client/sessions/connection.d.ts +118 -0
- package/dist/client/sessions/connection.js +162 -0
- package/dist/client/sessions/feed.d.ts +42 -0
- package/dist/client/sessions/feed.js +43 -0
- package/dist/client/sessions/sse.d.ts +47 -0
- package/dist/client/sessions/sse.js +112 -0
- package/dist/client/sessions/stream.d.ts +28 -0
- package/dist/client/sessions/stream.js +35 -0
- package/dist/client/sessions/watch.d.ts +34 -0
- package/dist/client/sessions/watch.js +40 -0
- package/dist/client/transport.d.ts +37 -0
- package/dist/client/transport.js +66 -0
- package/dist/contexts/command.d.ts +132 -0
- package/dist/contexts/command.js +20 -0
- package/dist/contexts/connection.d.ts +68 -0
- package/dist/contexts/connection.js +0 -0
- package/dist/contexts/job.d.ts +49 -0
- package/dist/contexts/job.js +0 -0
- package/dist/contexts/workflow.d.ts +147 -0
- package/dist/contexts/workflow.js +22 -0
- package/dist/errors/actor.d.ts +200 -0
- package/dist/errors/actor.js +271 -0
- package/dist/errors/content.d.ts +19 -0
- package/dist/errors/content.js +14 -0
- package/dist/errors/database.d.ts +22 -0
- package/dist/errors/database.js +23 -0
- package/dist/errors/events.d.ts +17 -0
- package/dist/errors/events.js +14 -0
- package/dist/errors/subscription.d.ts +12 -0
- package/dist/errors/subscription.js +8 -0
- package/dist/errors/workflow.d.ts +28 -0
- package/dist/errors/workflow.js +17 -0
- package/dist/handles/actors.d.ts +17 -0
- package/dist/handles/actors.js +7 -0
- package/dist/handles/content.d.ts +59 -0
- package/dist/handles/content.js +36 -0
- package/dist/handles/intents.d.ts +164 -0
- package/dist/handles/intents.js +214 -0
- package/dist/handles/run.d.ts +31 -0
- package/dist/handles/run.js +21 -0
- package/dist/handles/workflow.d.ts +27 -0
- package/dist/handles/workflow.js +23 -0
- package/dist/identity/caller.d.ts +105 -0
- package/dist/identity/caller.js +68 -0
- package/dist/identity/child.d.ts +18 -0
- package/dist/identity/child.js +39 -0
- package/dist/identity/command.d.ts +19 -0
- package/dist/identity/command.js +21 -0
- package/dist/identity/connection.d.ts +24 -0
- package/dist/identity/connection.js +29 -0
- package/dist/identity/content.d.ts +18 -0
- package/dist/identity/content.js +12 -0
- package/dist/identity/digest.d.ts +4 -0
- package/dist/identity/digest.js +5 -0
- package/dist/identity/execution.d.ts +32 -0
- package/dist/identity/execution.js +63 -0
- package/dist/identity/mint.d.ts +51 -0
- package/dist/identity/mint.js +76 -0
- package/dist/identity/version.d.ts +2 -0
- package/dist/identity/version.js +3 -0
- package/dist/index.d.ts +159 -0
- package/dist/index.js +97 -0
- package/dist/members/blob.d.ts +43 -0
- package/dist/members/blob.js +29 -0
- package/dist/members/command.d.ts +109 -0
- package/dist/members/command.js +61 -0
- package/dist/members/connection.d.ts +55 -0
- package/dist/members/connection.js +49 -0
- package/dist/members/event.d.ts +36 -0
- package/dist/members/event.js +24 -0
- package/dist/members/job.d.ts +157 -0
- package/dist/members/job.js +67 -0
- package/dist/members/payload.d.ts +93 -0
- package/dist/members/payload.js +145 -0
- package/dist/members/reducer.d.ts +64 -0
- package/dist/members/reducer.js +27 -0
- package/dist/members/stream.d.ts +36 -0
- package/dist/members/stream.js +14 -0
- package/dist/members/subscription.d.ts +182 -0
- package/dist/members/subscription.js +91 -0
- package/dist/members/workflow.d.ts +99 -0
- package/dist/members/workflow.js +2 -0
- package/dist/policies/access.d.ts +35 -0
- package/dist/policies/access.js +6 -0
- package/dist/policies/command.d.ts +127 -0
- package/dist/policies/command.js +45 -0
- package/dist/policies/job.d.ts +28 -0
- package/dist/policies/job.js +60 -0
- package/dist/policies/schedules.d.ts +33 -0
- package/dist/policies/schedules.js +131 -0
- package/dist/protocol/frames.d.ts +66 -0
- package/dist/protocol/frames.js +55 -0
- package/dist/protocol/inspection.d.ts +807 -0
- package/dist/protocol/inspection.js +243 -0
- package/dist/protocol/wire.d.ts +184 -0
- package/dist/protocol/wire.js +150 -0
- package/dist/runtime/actors.d.ts +155 -0
- package/dist/runtime/actors.js +4 -0
- package/dist/runtime/admission.d.ts +34 -0
- package/dist/runtime/admission.js +72 -0
- package/dist/runtime/adoption/backfill.d.ts +27 -0
- package/dist/runtime/adoption/backfill.js +144 -0
- package/dist/runtime/adoption/enforce.d.ts +55 -0
- package/dist/runtime/adoption/enforce.js +241 -0
- package/dist/runtime/adoption/observe.d.ts +43 -0
- package/dist/runtime/adoption/observe.js +139 -0
- package/dist/runtime/adoption/plan.d.ts +45 -0
- package/dist/runtime/adoption/plan.js +192 -0
- package/dist/runtime/adoption/startup.d.ts +32 -0
- package/dist/runtime/adoption/startup.js +76 -0
- package/dist/runtime/adoption/status.d.ts +23 -0
- package/dist/runtime/adoption/status.js +47 -0
- package/dist/runtime/adoption/target.d.ts +33 -0
- package/dist/runtime/adoption/target.js +49 -0
- package/dist/runtime/connections/holder.d.ts +221 -0
- package/dist/runtime/connections/holder.js +816 -0
- package/dist/runtime/connections/owner.d.ts +263 -0
- package/dist/runtime/connections/owner.js +896 -0
- package/dist/runtime/connections/protocol.d.ts +441 -0
- package/dist/runtime/connections/protocol.js +222 -0
- package/dist/runtime/connections/reads.d.ts +24 -0
- package/dist/runtime/connections/reads.js +19 -0
- package/dist/runtime/connections/streams.d.ts +62 -0
- package/dist/runtime/connections/streams.js +128 -0
- package/dist/runtime/connections/transport.d.ts +40 -0
- package/dist/runtime/connections/transport.js +68 -0
- package/dist/runtime/connections/watch.d.ts +52 -0
- package/dist/runtime/connections/watch.js +159 -0
- package/dist/runtime/content/grant.d.ts +34 -0
- package/dist/runtime/content/grant.js +58 -0
- package/dist/runtime/content/store.d.ts +63 -0
- package/dist/runtime/content/store.js +294 -0
- package/dist/runtime/cron/key.d.ts +2 -0
- package/dist/runtime/cron/key.js +2 -0
- package/dist/runtime/cron/schedule.d.ts +69 -0
- package/dist/runtime/cron/schedule.js +144 -0
- package/dist/runtime/database/bounded.d.ts +43 -0
- package/dist/runtime/database/bounded.js +108 -0
- package/dist/runtime/database/connection.d.ts +8 -0
- package/dist/runtime/database/connection.js +18 -0
- package/dist/runtime/database/coordination.d.ts +19 -0
- package/dist/runtime/database/coordination.js +72 -0
- package/dist/runtime/database/flock.d.ts +10 -0
- package/dist/runtime/database/flock.js +60 -0
- package/dist/runtime/database/gate.d.ts +26 -0
- package/dist/runtime/database/gate.js +54 -0
- package/dist/runtime/database/keepalive.d.ts +11 -0
- package/dist/runtime/database/keepalive.js +22 -0
- package/dist/runtime/database/migrations.d.ts +177 -0
- package/dist/runtime/database/migrations.js +1018 -0
- package/dist/runtime/database/neki/migrations.d.ts +31 -0
- package/dist/runtime/database/neki/migrations.js +276 -0
- package/dist/runtime/database/neki/session.d.ts +23 -0
- package/dist/runtime/database/neki/session.js +31 -0
- package/dist/runtime/database/pglite.d.ts +21 -0
- package/dist/runtime/database/pglite.js +74 -0
- package/dist/runtime/database/replica.d.ts +41 -0
- package/dist/runtime/database/replica.js +51 -0
- package/dist/runtime/database/shards.d.ts +21 -0
- package/dist/runtime/database/shards.js +37 -0
- package/dist/runtime/database/snapshot.d.ts +7 -0
- package/dist/runtime/database/snapshot.js +7 -0
- package/dist/runtime/database/tenancy.d.ts +69 -0
- package/dist/runtime/database/tenancy.js +145 -0
- package/dist/runtime/database/transient.d.ts +10 -0
- package/dist/runtime/database/transient.js +25 -0
- package/dist/runtime/drain.d.ts +132 -0
- package/dist/runtime/drain.js +109 -0
- package/dist/runtime/entity/mailbox.d.ts +86 -0
- package/dist/runtime/entity/mailbox.js +121 -0
- package/dist/runtime/entity/register.d.ts +424 -0
- package/dist/runtime/entity/register.js +669 -0
- package/dist/runtime/events/append.d.ts +192 -0
- package/dist/runtime/events/append.js +128 -0
- package/dist/runtime/events/cursor.d.ts +2 -0
- package/dist/runtime/events/cursor.js +5 -0
- package/dist/runtime/events/replay.d.ts +20 -0
- package/dist/runtime/events/replay.js +45 -0
- package/dist/runtime/feeds.d.ts +26 -0
- package/dist/runtime/feeds.js +100 -0
- package/dist/runtime/fleet/checks.d.ts +17 -0
- package/dist/runtime/fleet/checks.js +106 -0
- package/dist/runtime/fleet/maintainer.d.ts +38 -0
- package/dist/runtime/fleet/maintainer.js +383 -0
- package/dist/runtime/fleet/pgoutput.d.ts +41 -0
- package/dist/runtime/fleet/pgoutput.js +102 -0
- package/dist/runtime/fleet/setup.d.ts +36 -0
- package/dist/runtime/fleet/setup.js +58 -0
- package/dist/runtime/fleet/subscribe.d.ts +42 -0
- package/dist/runtime/fleet/subscribe.js +147 -0
- package/dist/runtime/index.d.ts +66 -0
- package/dist/runtime/index.js +37 -0
- package/dist/runtime/inspector/http.d.ts +19 -0
- package/dist/runtime/inspector/http.js +36 -0
- package/dist/runtime/inspector/layer.d.ts +46 -0
- package/dist/runtime/inspector/layer.js +180 -0
- package/dist/runtime/inspector/queries.d.ts +711 -0
- package/dist/runtime/inspector/queries.js +494 -0
- package/dist/runtime/jobs/attempt.d.ts +254 -0
- package/dist/runtime/jobs/attempt.js +413 -0
- package/dist/runtime/jobs/isolation.d.ts +20 -0
- package/dist/runtime/jobs/isolation.js +10 -0
- package/dist/runtime/jobs/progress.d.ts +95 -0
- package/dist/runtime/jobs/progress.js +144 -0
- package/dist/runtime/layer.d.ts +260 -0
- package/dist/runtime/layer.js +876 -0
- package/dist/runtime/members.d.ts +381 -0
- package/dist/runtime/members.js +8 -0
- package/dist/runtime/operators/audit.d.ts +64 -0
- package/dist/runtime/operators/audit.js +56 -0
- package/dist/runtime/operators/auth.d.ts +29 -0
- package/dist/runtime/operators/auth.js +42 -0
- package/dist/runtime/operators/export.d.ts +68 -0
- package/dist/runtime/operators/export.js +137 -0
- package/dist/runtime/operators/grants.d.ts +45 -0
- package/dist/runtime/operators/grants.js +40 -0
- package/dist/runtime/operators/repair.d.ts +206 -0
- package/dist/runtime/operators/repair.js +226 -0
- package/dist/runtime/operators/routes.d.ts +35 -0
- package/dist/runtime/operators/routes.js +190 -0
- package/dist/runtime/operators/seed.d.ts +123 -0
- package/dist/runtime/operators/seed.js +123 -0
- package/dist/runtime/payloads/versions.d.ts +65 -0
- package/dist/runtime/payloads/versions.js +240 -0
- package/dist/runtime/peering/authority.d.ts +42 -0
- package/dist/runtime/peering/authority.js +132 -0
- package/dist/runtime/peering/credentials.d.ts +21 -0
- package/dist/runtime/peering/credentials.js +13 -0
- package/dist/runtime/peering/transport.d.ts +51 -0
- package/dist/runtime/peering/transport.js +175 -0
- package/dist/runtime/queries.d.ts +18 -0
- package/dist/runtime/queries.js +169 -0
- package/dist/runtime/readiness.d.ts +36 -0
- package/dist/runtime/readiness.js +44 -0
- package/dist/runtime/registration.d.ts +58 -0
- package/dist/runtime/registration.js +186 -0
- package/dist/runtime/request.d.ts +158 -0
- package/dist/runtime/request.js +102 -0
- package/dist/runtime/retry.d.ts +8 -0
- package/dist/runtime/retry.js +11 -0
- package/dist/runtime/runner.d.ts +93 -0
- package/dist/runtime/runner.js +122 -0
- package/dist/runtime/storage/codec.d.ts +39 -0
- package/dist/runtime/storage/codec.js +41 -0
- package/dist/runtime/storage/generation.d.ts +69 -0
- package/dist/runtime/storage/generation.js +49 -0
- package/dist/runtime/storage/placements.d.ts +15 -0
- package/dist/runtime/storage/placements.js +38 -0
- package/dist/runtime/storage/platform.d.ts +6 -0
- package/dist/runtime/storage/platform.js +9 -0
- package/dist/runtime/storage/retention.d.ts +73 -0
- package/dist/runtime/storage/retention.js +158 -0
- package/dist/runtime/subscriptions/identity.d.ts +31 -0
- package/dist/runtime/subscriptions/identity.js +45 -0
- package/dist/runtime/subscriptions/relay.d.ts +175 -0
- package/dist/runtime/subscriptions/relay.js +763 -0
- package/dist/runtime/subscriptions/storage.d.ts +40 -0
- package/dist/runtime/subscriptions/storage.js +98 -0
- package/dist/runtime/sweeps.d.ts +39 -0
- package/dist/runtime/sweeps.js +54 -0
- package/dist/runtime/telemetry/defects.d.ts +57 -0
- package/dist/runtime/telemetry/defects.js +43 -0
- package/dist/runtime/telemetry/metrics.d.ts +52 -0
- package/dist/runtime/telemetry/metrics.js +138 -0
- package/dist/runtime/telemetry/routes.d.ts +19 -0
- package/dist/runtime/telemetry/routes.js +18 -0
- package/dist/runtime/telemetry/sampler.d.ts +26 -0
- package/dist/runtime/telemetry/sampler.js +101 -0
- package/dist/runtime/telemetry/spans.d.ts +38 -0
- package/dist/runtime/telemetry/spans.js +44 -0
- package/dist/runtime/telemetry/usage.d.ts +52 -0
- package/dist/runtime/telemetry/usage.js +30 -0
- package/dist/runtime/topology/admission.d.ts +13 -0
- package/dist/runtime/topology/admission.js +36 -0
- package/dist/runtime/topology/locks.d.ts +56 -0
- package/dist/runtime/topology/locks.js +81 -0
- package/dist/runtime/topology/messages.d.ts +15 -0
- package/dist/runtime/topology/messages.js +32 -0
- package/dist/runtime/turn/admission.d.ts +22 -0
- package/dist/runtime/turn/admission.js +41 -0
- package/dist/runtime/turn/blobs.d.ts +38 -0
- package/dist/runtime/turn/blobs.js +215 -0
- package/dist/runtime/turn/execute.d.ts +208 -0
- package/dist/runtime/turn/execute.js +972 -0
- package/dist/runtime/turn/group.d.ts +165 -0
- package/dist/runtime/turn/group.js +326 -0
- package/dist/runtime/turn/hooks.d.ts +44 -0
- package/dist/runtime/turn/hooks.js +28 -0
- package/dist/runtime/turn/outbox.d.ts +159 -0
- package/dist/runtime/turn/outbox.js +269 -0
- package/dist/runtime/turn/pipeline.d.ts +68 -0
- package/dist/runtime/turn/pipeline.js +83 -0
- package/dist/runtime/turn/receipt.d.ts +81 -0
- package/dist/runtime/turn/receipt.js +32 -0
- package/dist/runtime/turn/relay.d.ts +179 -0
- package/dist/runtime/turn/relay.js +685 -0
- package/dist/runtime/turn/rows.d.ts +43 -0
- package/dist/runtime/turn/rows.js +592 -0
- package/dist/runtime/workflows/compatibility.d.ts +125 -0
- package/dist/runtime/workflows/compatibility.js +285 -0
- package/dist/runtime/workflows/engine.d.ts +107 -0
- package/dist/runtime/workflows/engine.js +826 -0
- package/dist/runtime/workflows/manifest.d.ts +34 -0
- package/dist/runtime/workflows/manifest.js +39 -0
- package/dist/runtime/workflows/steps.d.ts +33 -0
- package/dist/runtime/workflows/steps.js +152 -0
- package/dist/serve/api.d.ts +99 -0
- package/dist/serve/api.js +403 -0
- package/dist/serve/assertion/binding.d.ts +41 -0
- package/dist/serve/assertion/binding.js +92 -0
- package/dist/serve/assertion/verify.d.ts +93 -0
- package/dist/serve/assertion/verify.js +189 -0
- package/dist/serve/auth.d.ts +200 -0
- package/dist/serve/auth.js +92 -0
- package/dist/serve/clock.d.ts +10 -0
- package/dist/serve/clock.js +25 -0
- package/dist/serve/jwt.d.ts +65 -0
- package/dist/serve/jwt.js +202 -0
- package/dist/serve/layer.d.ts +98 -0
- package/dist/serve/layer.js +809 -0
- package/dist/serve/mcp/endpoint.d.ts +39 -0
- package/dist/serve/mcp/endpoint.js +187 -0
- package/dist/serve/mcp/tools.d.ts +37 -0
- package/dist/serve/mcp/tools.js +125 -0
- package/dist/serve/origin.d.ts +6 -0
- package/dist/serve/origin.js +21 -0
- package/dist/serve/sessions/feed.d.ts +79 -0
- package/dist/serve/sessions/feed.js +115 -0
- package/dist/serve/sessions/socket.d.ts +56 -0
- package/dist/serve/sessions/socket.js +212 -0
- package/dist/serve/sessions/sse.d.ts +27 -0
- package/dist/serve/sessions/sse.js +26 -0
- package/dist/serve/sessions/stream.d.ts +9 -0
- package/dist/serve/sessions/stream.js +9 -0
- package/dist/serve/sessions/watch.d.ts +12 -0
- package/dist/serve/sessions/watch.js +11 -0
- package/dist/serve/wire.d.ts +16 -0
- package/dist/serve/wire.js +50 -0
- package/dist/state/blob.d.ts +71 -0
- package/dist/state/blob.js +0 -0
- package/dist/state/migration.d.ts +53 -0
- package/dist/state/migration.js +29 -0
- package/dist/tables/fleet.d.ts +170 -0
- package/dist/tables/fleet.js +214 -0
- package/dist/tables/owned.d.ts +250 -0
- package/dist/tables/owned.js +233 -0
- package/dist/testing/actor-test.d.ts +360 -0
- package/dist/testing/actor-test.js +337 -0
- package/dist/testing/cluster.d.ts +93 -0
- package/dist/testing/cluster.js +296 -0
- package/dist/testing/conformance/access.d.ts +5 -0
- package/dist/testing/conformance/access.js +531 -0
- package/dist/testing/conformance/admission.d.ts +11 -0
- package/dist/testing/conformance/admission.js +182 -0
- package/dist/testing/conformance/adoption.d.ts +2 -0
- package/dist/testing/conformance/adoption.js +1019 -0
- package/dist/testing/conformance/assertions.d.ts +202 -0
- package/dist/testing/conformance/assertions.js +849 -0
- package/dist/testing/conformance/batches.d.ts +41 -0
- package/dist/testing/conformance/batches.js +388 -0
- package/dist/testing/conformance/blobs.d.ts +14 -0
- package/dist/testing/conformance/blobs.js +405 -0
- package/dist/testing/conformance/capacity.d.ts +8 -0
- package/dist/testing/conformance/capacity.js +433 -0
- package/dist/testing/conformance/client.d.ts +5 -0
- package/dist/testing/conformance/client.js +719 -0
- package/dist/testing/conformance/cold-serve.d.ts +16 -0
- package/dist/testing/conformance/cold-serve.js +254 -0
- package/dist/testing/conformance/connections/actors.d.ts +1143 -0
- package/dist/testing/conformance/connections/actors.js +180 -0
- package/dist/testing/conformance/connections/harness.d.ts +1754 -0
- package/dist/testing/conformance/connections/harness.js +142 -0
- package/dist/testing/conformance/connections/holders.d.ts +4 -0
- package/dist/testing/conformance/connections/holders.js +165 -0
- package/dist/testing/conformance/connections/lifecycle.d.ts +4 -0
- package/dist/testing/conformance/connections/lifecycle.js +113 -0
- package/dist/testing/conformance/connections/limits.d.ts +4 -0
- package/dist/testing/conformance/connections/limits.js +127 -0
- package/dist/testing/conformance/connections/reauthorization.d.ts +4 -0
- package/dist/testing/conformance/connections/reauthorization.js +170 -0
- package/dist/testing/conformance/connections/resync.d.ts +4 -0
- package/dist/testing/conformance/connections/resync.js +360 -0
- package/dist/testing/conformance/connections/takeover.d.ts +4 -0
- package/dist/testing/conformance/connections/takeover.js +287 -0
- package/dist/testing/conformance/connections.d.ts +4 -0
- package/dist/testing/conformance/connections.js +15 -0
- package/dist/testing/conformance/content-blobs.d.ts +16 -0
- package/dist/testing/conformance/content-blobs.js +534 -0
- package/dist/testing/conformance/counter.d.ts +16 -0
- package/dist/testing/conformance/counter.js +813 -0
- package/dist/testing/conformance/cron.d.ts +5 -0
- package/dist/testing/conformance/cron.js +665 -0
- package/dist/testing/conformance/drain.d.ts +26 -0
- package/dist/testing/conformance/drain.js +540 -0
- package/dist/testing/conformance/effect-control.d.ts +38 -0
- package/dist/testing/conformance/effect-control.js +1059 -0
- package/dist/testing/conformance/effects.d.ts +23 -0
- package/dist/testing/conformance/effects.js +432 -0
- package/dist/testing/conformance/events.d.ts +28 -0
- package/dist/testing/conformance/events.js +335 -0
- package/dist/testing/conformance/export.d.ts +2 -0
- package/dist/testing/conformance/export.js +368 -0
- package/dist/testing/conformance/fleet.d.ts +444 -0
- package/dist/testing/conformance/fleet.js +1009 -0
- package/dist/testing/conformance/groups.d.ts +7 -0
- package/dist/testing/conformance/groups.js +353 -0
- package/dist/testing/conformance/heap.d.ts +3 -0
- package/dist/testing/conformance/heap.js +149 -0
- package/dist/testing/conformance/http.d.ts +2809 -0
- package/dist/testing/conformance/http.js +1234 -0
- package/dist/testing/conformance/inspection-views.d.ts +8 -0
- package/dist/testing/conformance/inspection-views.js +272 -0
- package/dist/testing/conformance/inspector.d.ts +7 -0
- package/dist/testing/conformance/inspector.js +650 -0
- package/dist/testing/conformance/mint.d.ts +58 -0
- package/dist/testing/conformance/mint.js +692 -0
- package/dist/testing/conformance/multi-runner.d.ts +8 -0
- package/dist/testing/conformance/multi-runner.js +403 -0
- package/dist/testing/conformance/neki/plan.d.ts +19 -0
- package/dist/testing/conformance/neki/plan.js +30 -0
- package/dist/testing/conformance/observability.d.ts +3 -0
- package/dist/testing/conformance/observability.js +343 -0
- package/dist/testing/conformance/offline.d.ts +4 -0
- package/dist/testing/conformance/offline.js +474 -0
- package/dist/testing/conformance/operator-harness.d.ts +57 -0
- package/dist/testing/conformance/operator-harness.js +78 -0
- package/dist/testing/conformance/operator.d.ts +3 -0
- package/dist/testing/conformance/operator.js +379 -0
- package/dist/testing/conformance/outbox-cross-shard.d.ts +14 -0
- package/dist/testing/conformance/outbox-cross-shard.js +160 -0
- package/dist/testing/conformance/outbox.d.ts +36 -0
- package/dist/testing/conformance/outbox.js +437 -0
- package/dist/testing/conformance/payload-migrations.d.ts +3 -0
- package/dist/testing/conformance/payload-migrations.js +612 -0
- package/dist/testing/conformance/pipeline.d.ts +3 -0
- package/dist/testing/conformance/pipeline.js +1040 -0
- package/dist/testing/conformance/placement.d.ts +22 -0
- package/dist/testing/conformance/placement.js +539 -0
- package/dist/testing/conformance/platform.d.ts +40 -0
- package/dist/testing/conformance/platform.js +101 -0
- package/dist/testing/conformance/progress.d.ts +39 -0
- package/dist/testing/conformance/progress.js +666 -0
- package/dist/testing/conformance/properties.d.ts +6 -0
- package/dist/testing/conformance/properties.js +295 -0
- package/dist/testing/conformance/protocols.d.ts +4 -0
- package/dist/testing/conformance/protocols.js +618 -0
- package/dist/testing/conformance/provider/advertise.d.ts +21 -0
- package/dist/testing/conformance/provider/advertise.js +44 -0
- package/dist/testing/conformance/read-your-writes.d.ts +20 -0
- package/dist/testing/conformance/read-your-writes.js +192 -0
- package/dist/testing/conformance/reducers.d.ts +8 -0
- package/dist/testing/conformance/reducers.js +258 -0
- package/dist/testing/conformance/relay.d.ts +42 -0
- package/dist/testing/conformance/relay.js +1115 -0
- package/dist/testing/conformance/restore.d.ts +43 -0
- package/dist/testing/conformance/restore.js +341 -0
- package/dist/testing/conformance/retention.d.ts +14 -0
- package/dist/testing/conformance/retention.js +463 -0
- package/dist/testing/conformance/rls.d.ts +24 -0
- package/dist/testing/conformance/rls.js +576 -0
- package/dist/testing/conformance/simulation.d.ts +31 -0
- package/dist/testing/conformance/simulation.js +167 -0
- package/dist/testing/conformance/single-shard.d.ts +2 -0
- package/dist/testing/conformance/single-shard.js +125 -0
- package/dist/testing/conformance/singleton.d.ts +3 -0
- package/dist/testing/conformance/singleton.js +293 -0
- package/dist/testing/conformance/statements.d.ts +60 -0
- package/dist/testing/conformance/statements.js +108 -0
- package/dist/testing/conformance/streams.d.ts +7 -0
- package/dist/testing/conformance/streams.js +280 -0
- package/dist/testing/conformance/subscriptions/access.d.ts +4 -0
- package/dist/testing/conformance/subscriptions/access.js +98 -0
- package/dist/testing/conformance/subscriptions/actors.d.ts +4910 -0
- package/dist/testing/conformance/subscriptions/actors.js +372 -0
- package/dist/testing/conformance/subscriptions/cluster.d.ts +4 -0
- package/dist/testing/conformance/subscriptions/cluster.js +89 -0
- package/dist/testing/conformance/subscriptions/delivery.d.ts +4 -0
- package/dist/testing/conformance/subscriptions/delivery.js +253 -0
- package/dist/testing/conformance/subscriptions/deploys.d.ts +4 -0
- package/dist/testing/conformance/subscriptions/deploys.js +162 -0
- package/dist/testing/conformance/subscriptions/epochs.d.ts +4 -0
- package/dist/testing/conformance/subscriptions/epochs.js +169 -0
- package/dist/testing/conformance/subscriptions/failures.d.ts +4 -0
- package/dist/testing/conformance/subscriptions/failures.js +108 -0
- package/dist/testing/conformance/subscriptions/feeds.d.ts +4 -0
- package/dist/testing/conformance/subscriptions/feeds.js +218 -0
- package/dist/testing/conformance/subscriptions/harness.d.ts +124 -0
- package/dist/testing/conformance/subscriptions/harness.js +143 -0
- package/dist/testing/conformance/subscriptions/operator.d.ts +4 -0
- package/dist/testing/conformance/subscriptions/operator.js +128 -0
- package/dist/testing/conformance/subscriptions/retention.d.ts +4 -0
- package/dist/testing/conformance/subscriptions/retention.js +288 -0
- package/dist/testing/conformance/subscriptions/routing.d.ts +4 -0
- package/dist/testing/conformance/subscriptions/routing.js +179 -0
- package/dist/testing/conformance/subscriptions.d.ts +4 -0
- package/dist/testing/conformance/subscriptions.js +19 -0
- package/dist/testing/conformance/tables.d.ts +125 -0
- package/dist/testing/conformance/tables.js +664 -0
- package/dist/testing/conformance/transports/actors.d.ts +1907 -0
- package/dist/testing/conformance/transports/actors.js +163 -0
- package/dist/testing/conformance/transports/client.d.ts +3 -0
- package/dist/testing/conformance/transports/client.js +237 -0
- package/dist/testing/conformance/transports/feeds.d.ts +3 -0
- package/dist/testing/conformance/transports/feeds.js +232 -0
- package/dist/testing/conformance/transports/harness.d.ts +93 -0
- package/dist/testing/conformance/transports/harness.js +84 -0
- package/dist/testing/conformance/transports/streams.d.ts +3 -0
- package/dist/testing/conformance/transports/streams.js +96 -0
- package/dist/testing/conformance/transports/websocket.d.ts +3 -0
- package/dist/testing/conformance/transports/websocket.js +384 -0
- package/dist/testing/conformance/transports/wire.d.ts +141 -0
- package/dist/testing/conformance/transports/wire.js +204 -0
- package/dist/testing/conformance/transports.d.ts +3 -0
- package/dist/testing/conformance/transports.js +11 -0
- package/dist/testing/conformance/watch.d.ts +59 -0
- package/dist/testing/conformance/watch.js +879 -0
- package/dist/testing/conformance/workflow-engine.d.ts +97 -0
- package/dist/testing/conformance/workflow-engine.js +253 -0
- package/dist/testing/conformance/workflow-versions.d.ts +3 -0
- package/dist/testing/conformance/workflow-versions.js +545 -0
- package/dist/testing/conformance/workflows/access.d.ts +4 -0
- package/dist/testing/conformance/workflows/access.js +147 -0
- package/dist/testing/conformance/workflows/actors.d.ts +2317 -0
- package/dist/testing/conformance/workflows/actors.js +305 -0
- package/dist/testing/conformance/workflows/basics.d.ts +4 -0
- package/dist/testing/conformance/workflows/basics.js +144 -0
- package/dist/testing/conformance/workflows/engine.d.ts +4 -0
- package/dist/testing/conformance/workflows/engine.js +80 -0
- package/dist/testing/conformance/workflows/guards.d.ts +4 -0
- package/dist/testing/conformance/workflows/guards.js +172 -0
- package/dist/testing/conformance/workflows/harness.d.ts +14 -0
- package/dist/testing/conformance/workflows/harness.js +44 -0
- package/dist/testing/conformance/workflows/recovery.d.ts +4 -0
- package/dist/testing/conformance/workflows/recovery.js +181 -0
- package/dist/testing/conformance/workflows/starts.d.ts +4 -0
- package/dist/testing/conformance/workflows/starts.js +57 -0
- package/dist/testing/conformance/workflows/suspension.d.ts +4 -0
- package/dist/testing/conformance/workflows/suspension.js +106 -0
- package/dist/testing/conformance/workflows/waits.d.ts +4 -0
- package/dist/testing/conformance/workflows/waits.js +284 -0
- package/dist/testing/conformance/workflows.d.ts +4 -0
- package/dist/testing/conformance/workflows.js +19 -0
- package/dist/testing/conformance.d.ts +330 -0
- package/dist/testing/conformance.js +364 -0
- package/dist/testing/database.d.ts +31 -0
- package/dist/testing/database.js +70 -0
- package/dist/testing/foundation.d.ts +41 -0
- package/dist/testing/foundation.js +517 -0
- package/dist/testing/index.d.ts +20 -0
- package/dist/testing/index.js +12 -0
- package/dist/testing/property.d.ts +40 -0
- package/dist/testing/property.js +95 -0
- package/dist/testing/simulate-cluster.d.ts +112 -0
- package/dist/testing/simulate-cluster.js +257 -0
- package/dist/testing/simulate.d.ts +90 -0
- package/dist/testing/simulate.js +127 -0
- package/package.json +1 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { isDeepStrictEqual } from "node:util";
|
|
2
|
+
import { Config, Effect, Predicate, Random, Result, Schema } from "effect";
|
|
3
|
+
import { Arbitrary } from "effect";
|
|
4
|
+
/** The seed every property runs under unless `PROPERTY_SEED` overrides it. */
|
|
5
|
+
export const PROPERTY_SEED = "56";
|
|
6
|
+
/** Generated cases per property unless `PROPERTY_RUNS` overrides it. */
|
|
7
|
+
export const PROPERTY_RUNS = 1_000;
|
|
8
|
+
/**
|
|
9
|
+
* The seed for this run: `PROPERTY_SEED`, or a fresh one when it is `random`.
|
|
10
|
+
* Rerunning with the printed seed regenerates the same inputs.
|
|
11
|
+
*/
|
|
12
|
+
const propertySeed = Effect.gen(function* () {
|
|
13
|
+
const configured = yield* Config.String("PROPERTY_SEED").pipe(Config.withDefault(PROPERTY_SEED));
|
|
14
|
+
if (configured !== "random")
|
|
15
|
+
return configured;
|
|
16
|
+
return String(yield* Random.nextIntBetween(0, 2 ** 31 - 1));
|
|
17
|
+
}).pipe(Effect.orDie);
|
|
18
|
+
const propertyRuns = Config.Int("PROPERTY_RUNS").pipe(Config.withDefault(PROPERTY_RUNS), Effect.orDie);
|
|
19
|
+
/**
|
|
20
|
+
* Checks `options.property` against `options.arbitrary` for a bounded, seeded number of runs
|
|
21
|
+
* and dies with the seed and the shrunk counterexample if it fails, so a
|
|
22
|
+
* failure reproduces with `PROPERTY_SEED=<seed>`. Returns the executed runs.
|
|
23
|
+
*/
|
|
24
|
+
export const checkProperty = (options) => Effect.gen(function* () {
|
|
25
|
+
const seed = yield* propertySeed;
|
|
26
|
+
const runs = options.runs ?? (yield* propertyRuns);
|
|
27
|
+
const result = yield* Arbitrary.checkEffect(options.arbitrary, options.property, {
|
|
28
|
+
seed,
|
|
29
|
+
runs,
|
|
30
|
+
});
|
|
31
|
+
if (Predicate.isTagged(result, "Passed") && result.runs === runs)
|
|
32
|
+
return result.runs;
|
|
33
|
+
return yield* Effect.die(new Error(`Property "${options.name}" failed with PROPERTY_SEED=${seed}\n${Arbitrary.formatCheckFailure(result) ?? result._tag}`));
|
|
34
|
+
});
|
|
35
|
+
/** The combiner that lets the runtime fold consecutive queued calls into one turn. */
|
|
36
|
+
const batchOf = (reducer) => reducer.batch;
|
|
37
|
+
/**
|
|
38
|
+
* Runs `reduce` on a private copy of `state`, as the runtime does, and
|
|
39
|
+
* returns the next state only when it succeeded and satisfies the state
|
|
40
|
+
* schema; a declared failure, a throw, or an invalid state is `undefined`.
|
|
41
|
+
*/
|
|
42
|
+
const reduceValid = (reducer, valid, state, input) => {
|
|
43
|
+
try {
|
|
44
|
+
const reduced = reducer.reduce(structuredClone(state), input);
|
|
45
|
+
return Result.isSuccess(reduced) && valid(reduced.success) ? reduced.success : undefined;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Checks a batch reducer's ordered fold law over generated states and input
|
|
53
|
+
* lists: reducing the inputs one at a time, in order, and reducing their
|
|
54
|
+
* in-order combination once must both succeed with a valid state, and the two
|
|
55
|
+
* states must be equal. The law is about order-preserving folding, not
|
|
56
|
+
* commutativity, so an order-sensitive combine such as appending passes. A
|
|
57
|
+
* reducer that fails or throws for either path fails the check, because the
|
|
58
|
+
* runtime only folds calls whose reduction cannot fail. States and inputs
|
|
59
|
+
* default to their schemas' arbitraries; lists hold 1 to `maxInputs` inputs
|
|
60
|
+
* (default 8). Returns the executed runs, and dies with a reproducible seed on
|
|
61
|
+
* failure.
|
|
62
|
+
*/
|
|
63
|
+
export const checkBatchLaw = (options) => {
|
|
64
|
+
const { reducer } = options;
|
|
65
|
+
const batch = batchOf(reducer);
|
|
66
|
+
if (batch === undefined)
|
|
67
|
+
return Effect.die(new Error(`Reducer ${reducer.tag} does not declare batch folding`));
|
|
68
|
+
const stateSchema = Schema.Struct(reducer.state.fields);
|
|
69
|
+
const valid = Schema.is(stateSchema);
|
|
70
|
+
const state = options.state ?? Arbitrary.schema(stateSchema);
|
|
71
|
+
const input = options.input ?? Arbitrary.schema(reducer.payload);
|
|
72
|
+
return checkProperty({
|
|
73
|
+
name: `batch law of ${reducer.tag}`,
|
|
74
|
+
runs: options.runs,
|
|
75
|
+
arbitrary: Arbitrary.all([
|
|
76
|
+
state,
|
|
77
|
+
Arbitrary.array(input, { minLength: 1, maxLength: options.maxInputs ?? 8 }),
|
|
78
|
+
]),
|
|
79
|
+
property: ([initial, inputs]) => {
|
|
80
|
+
let sequential = initial;
|
|
81
|
+
for (const next of inputs)
|
|
82
|
+
if (sequential !== undefined)
|
|
83
|
+
sequential = reduceValid(reducer, valid, sequential, next);
|
|
84
|
+
let combined;
|
|
85
|
+
try {
|
|
86
|
+
combined = inputs.reduce((first, second) => batch.combine(first, second));
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
const folded = reduceValid(reducer, valid, initial, combined);
|
|
92
|
+
return (sequential !== undefined && folded !== undefined && isDeepStrictEqual(sequential, folded));
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { Cause, Duration, Effect } from "effect";
|
|
2
|
+
import { ActorError } from "../errors/actor.ts";
|
|
3
|
+
import { ActorCluster, type RunnerServices } from "./cluster.ts";
|
|
4
|
+
/**
|
|
5
|
+
* A fault `ActorTest.simulateCluster` injects into one command. The turn is
|
|
6
|
+
* the one the command runs on the runner that owns its actor; the caller
|
|
7
|
+
* enters through a seeded runner, which may or may not be that owner.
|
|
8
|
+
* - `crashBeforeCommit` and `crashAfterCommit`: the turn dies at that point, so it rolls back or
|
|
9
|
+
* its reply is lost, and the command id is sent again.
|
|
10
|
+
* - `dropReply`: the caller discards the reply it got and sends the same command id again.
|
|
11
|
+
* - `runnerKill`: the owner is killed with its turn paused before or after COMMIT, by seed. The
|
|
12
|
+
* command id goes to a surviving runner, which waits for the dead runner's shard lock to
|
|
13
|
+
* expire, and the killed runner starts again afterwards.
|
|
14
|
+
* - `heartbeatLoss`: the owner stops refreshing its shard locks with its turn paused before COMMIT.
|
|
15
|
+
* A rival runner takes the shard once the lock expires and commits the same command id; the
|
|
16
|
+
* first turn's COMMIT then meets the generation fence.
|
|
17
|
+
* - `connectionLoss`: every runner's database connections are cut at once and reconnect to the same
|
|
18
|
+
* database. The owner's turn is cut before COMMIT, when the transaction rolls back, or after the
|
|
19
|
+
* database made the COMMIT and before its reply arrived, when the runner cannot know the outcome,
|
|
20
|
+
* by seed. The command id is sent again, and a receipt resolves which of the two happened.
|
|
21
|
+
* - `primaryFailover`: `connectionLoss`, and then the database primary is killed and a standby
|
|
22
|
+
* promoted, so the reconnecting runners find the promoted standby. It needs the `primary` option,
|
|
23
|
+
* and happens once, on one seeded command of `commands`, since a promoted standby has no standby
|
|
24
|
+
* of its own to fail over to again.
|
|
25
|
+
*/
|
|
26
|
+
export type ClusterSimulationFault = "crashBeforeCommit" | "crashAfterCommit" | "dropReply" | "runnerKill" | "heartbeatLoss" | "connectionLoss" | "primaryFailover";
|
|
27
|
+
export interface ClusterSimulationOptions {
|
|
28
|
+
/** Every draw, and so the whole fault schedule, follows from it. */
|
|
29
|
+
readonly seed: string;
|
|
30
|
+
readonly faults: ReadonlyArray<ClusterSimulationFault>;
|
|
31
|
+
/** Chance that a command gets a fault. Default 0.5. */
|
|
32
|
+
readonly faultRate?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Kills the primary, promotes a standby, and moves the address the runners
|
|
35
|
+
* dial to it, once the runners' connections are cut; `primaryFailover` runs it.
|
|
36
|
+
*/
|
|
37
|
+
readonly primary?: Effect.Effect<void>;
|
|
38
|
+
/**
|
|
39
|
+
* How many commands the program sends. `primaryFailover` picks one of them,
|
|
40
|
+
* and the run fails if the program sends fewer.
|
|
41
|
+
*/
|
|
42
|
+
readonly commands?: number;
|
|
43
|
+
/** How long a caller waits for one attempt before sending its command id again. Default 10 seconds. */
|
|
44
|
+
readonly attempt?: Duration.Input;
|
|
45
|
+
/** How long one command may take to commit. Default 2 minutes. */
|
|
46
|
+
readonly within?: Duration.Input;
|
|
47
|
+
/** How far every runner's clock moves to settle outstanding deliveries. Default 1 minute per round. */
|
|
48
|
+
readonly settle?: Duration.Input;
|
|
49
|
+
}
|
|
50
|
+
export interface ClusterSimulationStep {
|
|
51
|
+
readonly label: string;
|
|
52
|
+
readonly commandId: string;
|
|
53
|
+
readonly fault: ClusterSimulationFault | "none";
|
|
54
|
+
/** The runner the caller first sent the command through. */
|
|
55
|
+
readonly runner: number;
|
|
56
|
+
/** Where a `runnerKill` cuts the turn; `beforeCommit` for every other fault except `crashAfterCommit`. */
|
|
57
|
+
readonly point: "beforeCommit" | "afterCommit";
|
|
58
|
+
/** Whether a `connectionLoss` or `primaryFailover` lets the database make the COMMIT before the cut. */
|
|
59
|
+
readonly landed: boolean;
|
|
60
|
+
}
|
|
61
|
+
export interface ClusterSimulationReport {
|
|
62
|
+
readonly seed: string;
|
|
63
|
+
readonly steps: ReadonlyArray<ClusterSimulationStep>;
|
|
64
|
+
}
|
|
65
|
+
export interface ClusterSimulation {
|
|
66
|
+
readonly seed: string;
|
|
67
|
+
/**
|
|
68
|
+
* Runs one command through a seeded runner under the seed's next fault,
|
|
69
|
+
* with a command id minted for it, and sends that id again until a receipt
|
|
70
|
+
* answers. `effect` must get its handles itself, since it runs on whichever
|
|
71
|
+
* runner carries it, and must be a single command call, so it commits one
|
|
72
|
+
* receipt.
|
|
73
|
+
*/
|
|
74
|
+
readonly command: <A, E, R>(label: string, effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E | ActorError | Cause.TimeoutError, Exclude<R, RunnerServices>>;
|
|
75
|
+
/** A seeded integer in `[min, max]`. */
|
|
76
|
+
readonly int: (min: number, max: number) => Effect.Effect<number>;
|
|
77
|
+
/** A seeded element of a non-empty list. */
|
|
78
|
+
readonly pick: <A>(values: readonly [A, ...Array<A>]) => Effect.Effect<A>;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Runs `program` on `cluster` under a fault schedule drawn from
|
|
82
|
+
* `options.seed`, then checks that every command committed exactly one
|
|
83
|
+
* receipt and no due or attempted outbox row was left undelivered. A failure
|
|
84
|
+
* dies with the seed. Rerunning it repeats the program's choices and each
|
|
85
|
+
* command's entry runner and fault; which runner owns an actor depends on
|
|
86
|
+
* runner addresses, which change from run to run, and command ids are minted
|
|
87
|
+
* fresh. Settling advances every runner's clock, so simulate once per
|
|
88
|
+
* cluster after any runner has restarted: a runner that starts after the
|
|
89
|
+
* settling has an earlier clock than the others, and a command id minted on a
|
|
90
|
+
* runner ahead of it is in the future to it.
|
|
91
|
+
*/
|
|
92
|
+
export declare const simulateCluster: (cluster: ActorCluster["Service"]) => <E, R>(options: ClusterSimulationOptions, program: (simulation: ClusterSimulation) => Effect.Effect<void, E, R>) => Effect.Effect<ClusterSimulationReport, never, R>;
|
|
93
|
+
/** Seeds pull requests run on a cluster: `0` and `1`. */
|
|
94
|
+
export declare const CLUSTER_SIMULATION_SEEDS = 2;
|
|
95
|
+
/** Seeds the nightly run covers on a cluster: about a minute each. */
|
|
96
|
+
export declare const NIGHTLY_CLUSTER_SIMULATION_SEEDS = 6;
|
|
97
|
+
/** Seeds pull requests run through a real primary failover, each on a primary and standby of its own: `0`. */
|
|
98
|
+
export declare const FAILOVER_SIMULATION_SEEDS = 1;
|
|
99
|
+
/** Seeds the nightly run puts through a real primary failover: under a minute each. */
|
|
100
|
+
export declare const NIGHTLY_FAILOVER_SIMULATION_SEEDS = 3;
|
|
101
|
+
/**
|
|
102
|
+
* The seeds this run simulates on a cluster: `CLUSTER_SIMULATION_SEEDS` of
|
|
103
|
+
* them counted up from `SIMULATION_SEED_BASE`. A run whose `PROPERTY_SEED` is
|
|
104
|
+
* `random`, as the nightly run's is, defaults to
|
|
105
|
+
* `NIGHTLY_CLUSTER_SIMULATION_SEEDS` seeds from a base it draws and prints,
|
|
106
|
+
* so each night covers seeds no other night did; every other run defaults to
|
|
107
|
+
* `CLUSTER_SIMULATION_SEEDS` from 0. A failure names its seed; rerun it with
|
|
108
|
+
* `CLUSTER_SIMULATION_SEEDS=1 SIMULATION_SEED_BASE=<seed>`.
|
|
109
|
+
*/
|
|
110
|
+
export declare const clusterSimulationSeeds: Effect.Effect<string[], never, never>;
|
|
111
|
+
/** The seeds for the failover drill, chosen like `clusterSimulationSeeds` from `FAILOVER_SIMULATION_SEEDS`. */
|
|
112
|
+
export declare const failoverSimulationSeeds: Effect.Effect<string[], never, never>;
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { Cause, Config, Console, DateTime, Duration, Effect, Exit, Fiber, Option, Predicate, Random, Schedule, Schema, } from "effect";
|
|
2
|
+
import { SqlError } from "effect/sql";
|
|
3
|
+
import { Actor, Actors } from "../index.js";
|
|
4
|
+
import { ActorError } from "../errors/actor.js";
|
|
5
|
+
import { ActorTest } from "./actor-test.js";
|
|
6
|
+
import { ActorCluster } from "./cluster.js";
|
|
7
|
+
import { conclude, generator, SETTLE_ROUNDS } from "./simulate.js";
|
|
8
|
+
const isActorError = Schema.is(ActorError);
|
|
9
|
+
/**
|
|
10
|
+
* Runs `program` on `cluster` under a fault schedule drawn from
|
|
11
|
+
* `options.seed`, then checks that every command committed exactly one
|
|
12
|
+
* receipt and no due or attempted outbox row was left undelivered. A failure
|
|
13
|
+
* dies with the seed. Rerunning it repeats the program's choices and each
|
|
14
|
+
* command's entry runner and fault; which runner owns an actor depends on
|
|
15
|
+
* runner addresses, which change from run to run, and command ids are minted
|
|
16
|
+
* fresh. Settling advances every runner's clock, so simulate once per
|
|
17
|
+
* cluster after any runner has restarted: a runner that starts after the
|
|
18
|
+
* settling has an earlier clock than the others, and a command id minted on a
|
|
19
|
+
* runner ahead of it is in the future to it.
|
|
20
|
+
*/
|
|
21
|
+
export const simulateCluster = (cluster) => (options, program) => Effect.gen(function* () {
|
|
22
|
+
const draw = generator(options.seed);
|
|
23
|
+
const rate = options.faultRate ?? 0.5;
|
|
24
|
+
const attempt = Duration.fromInputUnsafe(options.attempt ?? "10 seconds");
|
|
25
|
+
const within = Duration.fromInputUnsafe(options.within ?? "2 minutes");
|
|
26
|
+
const settle = options.settle ?? "1 minute";
|
|
27
|
+
const steps = [];
|
|
28
|
+
const violations = [];
|
|
29
|
+
const runners = Array.from({ length: cluster.runners }, (_, index) => index);
|
|
30
|
+
const on = cluster.on;
|
|
31
|
+
const planned = options.faults.includes("primaryFailover");
|
|
32
|
+
const others = options.faults.filter((fault) => fault !== "primaryFailover");
|
|
33
|
+
if (runners.length < 2)
|
|
34
|
+
return yield* Effect.die(new Error("ActorTest.simulateCluster needs at least two runners"));
|
|
35
|
+
if (planned && options.primary === undefined)
|
|
36
|
+
return yield* Effect.die(new Error("primaryFailover needs the primary option"));
|
|
37
|
+
if (planned && (options.commands === undefined || options.commands < 1))
|
|
38
|
+
return yield* Effect.die(new Error("primaryFailover needs the number of commands"));
|
|
39
|
+
const failoverAt = planned ? Math.floor(draw() * options.commands) : -1;
|
|
40
|
+
const eachRunner = (effect) => Effect.forEach(runners, (runner) => on(runner)(effect));
|
|
41
|
+
const clearFaults = ActorTest.use((test) => test.clearFaults);
|
|
42
|
+
const clocks = (yield* eachRunner(ActorTest.use((test) => test.now))).map(DateTime.toEpochMillis);
|
|
43
|
+
if (Math.max(...clocks) - Math.min(...clocks) > 1_000)
|
|
44
|
+
return yield* Effect.die(new Error("ActorTest.simulateCluster needs runners whose clocks agree; an earlier simulation settled some runners' clocks ahead of a restarted one, so simulate once per cluster"));
|
|
45
|
+
/** The cluster's own pool reconnects through a failover like any other, so a read that meets one is retried. */
|
|
46
|
+
const read = (query) => query.pipe(Effect.retry({ schedule: Schedule.spaced("200 millis"), times: 50 }), Effect.orDie);
|
|
47
|
+
/**
|
|
48
|
+
* Minting a command id reads the database clock, which a failover
|
|
49
|
+
* briefly takes away, so it is retried. A crash fault is queued on every
|
|
50
|
+
* runner, and one of them takes it; if all of them still hold theirs,
|
|
51
|
+
* the turn never reached its point.
|
|
52
|
+
*/
|
|
53
|
+
const command = (label, effect) => Effect.gen(function* () {
|
|
54
|
+
const fault = steps.length === failoverAt
|
|
55
|
+
? "primaryFailover"
|
|
56
|
+
: others.length === 0 || draw() >= rate
|
|
57
|
+
? "none"
|
|
58
|
+
: others[Math.floor(draw() * others.length)];
|
|
59
|
+
const entry = Math.floor(draw() * runners.length);
|
|
60
|
+
const point = fault === "crashAfterCommit" || (fault === "runnerKill" && draw() < 0.5)
|
|
61
|
+
? "afterCommit"
|
|
62
|
+
: "beforeCommit";
|
|
63
|
+
const landed = (fault === "connectionLoss" || fault === "primaryFailover") && draw() < 0.5;
|
|
64
|
+
const commandId = yield* on(entry)(Effect.gen(function* () {
|
|
65
|
+
return yield* (yield* Actors).mintCommandId;
|
|
66
|
+
})).pipe(Effect.retry({
|
|
67
|
+
while: (error) => error.isRetryable,
|
|
68
|
+
schedule: Schedule.spaced("200 millis"),
|
|
69
|
+
times: 100,
|
|
70
|
+
}), Effect.orDie);
|
|
71
|
+
steps.push({ label, commandId, fault, runner: entry, point, landed });
|
|
72
|
+
const call = effect.pipe(Actor.commandId(commandId));
|
|
73
|
+
const send = (runner) => on(runner)(call).pipe(Effect.timeout(attempt));
|
|
74
|
+
/**
|
|
75
|
+
* Sends the same id through each runner in turn, skipping `avoid`,
|
|
76
|
+
* until a receipt answers; only the command's own declared failures end it.
|
|
77
|
+
*/
|
|
78
|
+
const deliver = (from, avoid) => {
|
|
79
|
+
const order = runners.filter((runner) => runner !== avoid);
|
|
80
|
+
const start = Math.max(order.indexOf(from), 0);
|
|
81
|
+
return Effect.gen(function* () {
|
|
82
|
+
for (let round = 0;; round++) {
|
|
83
|
+
const exit = yield* Effect.exit(send(order[(start + round) % order.length]));
|
|
84
|
+
if (Exit.isSuccess(exit))
|
|
85
|
+
return exit.value;
|
|
86
|
+
const error = Cause.findErrorOption(exit.cause);
|
|
87
|
+
const resendable = Option.isNone(error) ||
|
|
88
|
+
Predicate.isTagged(error.value, "TimeoutError") ||
|
|
89
|
+
(isActorError(error.value) && error.value.isRetryable);
|
|
90
|
+
if (!resendable)
|
|
91
|
+
return yield* Effect.failCause(exit.cause);
|
|
92
|
+
yield* Effect.sleep("100 millis");
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Whichever runner runs this command's turn reaches its pause, so
|
|
98
|
+
* every runner holds one and the others' are cleared once the owner is known.
|
|
99
|
+
*/
|
|
100
|
+
const holdTurn = Effect.gen(function* () {
|
|
101
|
+
const paused = yield* Effect.forEach(runners, (runner) => on(runner)(ActorTest.use((test) => test.pauseNext(point, { commandId }))));
|
|
102
|
+
const first = yield* Effect.forkChild(Effect.exit(send(entry)));
|
|
103
|
+
const owner = yield* Effect.raceAll(paused.map((pause, runner) => Effect.as(pause.reached, runner))).pipe(Effect.timeoutOrElse({
|
|
104
|
+
duration: within,
|
|
105
|
+
orElse: () => Effect.die(new Error(`${label} (${commandId}) never reached ${point}`)),
|
|
106
|
+
}));
|
|
107
|
+
yield* Effect.forEach(runners.filter((runner) => runner !== owner), (runner) => on(runner)(clearFaults));
|
|
108
|
+
return { owner, first, release: paused[owner].release };
|
|
109
|
+
});
|
|
110
|
+
const survivor = (owner) => entry === owner ? (owner + 1) % runners.length : entry;
|
|
111
|
+
if (fault === "none")
|
|
112
|
+
return yield* deliver(entry);
|
|
113
|
+
if (fault === "dropReply") {
|
|
114
|
+
yield* Effect.exit(send(entry));
|
|
115
|
+
return yield* deliver(entry);
|
|
116
|
+
}
|
|
117
|
+
if (fault === "crashBeforeCommit" || fault === "crashAfterCommit") {
|
|
118
|
+
yield* eachRunner(ActorTest.use((test) => test.crashNext(point, { commandId })));
|
|
119
|
+
const result = yield* deliver(entry);
|
|
120
|
+
const left = (yield* eachRunner(clearFaults)).flat();
|
|
121
|
+
if (left.length === runners.length)
|
|
122
|
+
violations.push(`${label} (${commandId}) never reached its ${point} crash`);
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
if (fault === "runnerKill") {
|
|
126
|
+
const { owner, first, release } = yield* holdTurn;
|
|
127
|
+
yield* cluster.kill(owner);
|
|
128
|
+
yield* release;
|
|
129
|
+
const result = yield* deliver(survivor(owner), owner);
|
|
130
|
+
yield* Fiber.interrupt(first);
|
|
131
|
+
yield* cluster.restart(owner);
|
|
132
|
+
yield* cluster.ready;
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
if (fault === "heartbeatLoss") {
|
|
136
|
+
const { owner, first, release } = yield* holdTurn;
|
|
137
|
+
const heartbeat = yield* cluster.pauseHeartbeat(owner);
|
|
138
|
+
const result = yield* deliver(survivor(owner), owner);
|
|
139
|
+
yield* release;
|
|
140
|
+
yield* Fiber.join(first);
|
|
141
|
+
yield* heartbeat.resume;
|
|
142
|
+
yield* cluster.ready;
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
const { first, release } = yield* holdTurn;
|
|
146
|
+
if (!landed) {
|
|
147
|
+
yield* cluster.failover;
|
|
148
|
+
yield* release;
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
yield* cluster.holdReplies;
|
|
152
|
+
yield* release;
|
|
153
|
+
yield* read(cluster.sql `
|
|
154
|
+
SELECT count(*)::integer AS count FROM actor_receipts
|
|
155
|
+
WHERE tenant_id = ${cluster.tenant} AND command_id = ${commandId}`).pipe(Effect.repeat({
|
|
156
|
+
until: ([receipts]) => receipts.count > 0,
|
|
157
|
+
schedule: Schedule.spaced("20 millis"),
|
|
158
|
+
}), Effect.timeoutOrElse({
|
|
159
|
+
duration: within,
|
|
160
|
+
orElse: () => Effect.die(new Error(`${label} (${commandId}) never committed`)),
|
|
161
|
+
}));
|
|
162
|
+
yield* cluster.failover;
|
|
163
|
+
}
|
|
164
|
+
if (fault === "primaryFailover")
|
|
165
|
+
yield* options.primary;
|
|
166
|
+
const settled = yield* Fiber.join(first);
|
|
167
|
+
return Exit.isSuccess(settled) ? settled.value : yield* deliver(entry);
|
|
168
|
+
}).pipe(Effect.timeoutOrElse({
|
|
169
|
+
duration: within,
|
|
170
|
+
orElse: () => Effect.die(new Error(`${label} did not commit within ${Duration.format(within)}`)),
|
|
171
|
+
}));
|
|
172
|
+
const simulation = {
|
|
173
|
+
seed: options.seed,
|
|
174
|
+
int: (min, max) => Effect.sync(() => min + Math.floor(draw() * (max - min + 1))),
|
|
175
|
+
pick: (values) => Effect.sync(() => values[Math.floor(draw() * values.length)]),
|
|
176
|
+
command,
|
|
177
|
+
};
|
|
178
|
+
const run = Effect.gen(function* () {
|
|
179
|
+
yield* program(simulation);
|
|
180
|
+
if (steps.length === 0)
|
|
181
|
+
violations.push("the program sent no command");
|
|
182
|
+
if (planned && steps.length <= failoverAt)
|
|
183
|
+
violations.push(`the primary failover planned for command ${failoverAt} never happened`);
|
|
184
|
+
/**
|
|
185
|
+
* A row that was ever attempted is still in flight, while one never
|
|
186
|
+
* attempted and not yet due is a timer the program scheduled.
|
|
187
|
+
*/
|
|
188
|
+
const pending = read(Effect.gen(function* () {
|
|
189
|
+
const now = DateTime.toEpochMillis(yield* on(0)(ActorTest.use((test) => test.now)));
|
|
190
|
+
const [rows] = yield* cluster.sql `
|
|
191
|
+
SELECT count(*)::integer AS count FROM actor_outbox
|
|
192
|
+
WHERE tenant_id = ${cluster.tenant} AND (due_at_ms <= ${now} OR attempts > 0)`;
|
|
193
|
+
return rows.count;
|
|
194
|
+
}));
|
|
195
|
+
let unsettled = Number.POSITIVE_INFINITY;
|
|
196
|
+
for (let round = 0; round < SETTLE_ROUNDS && unsettled > 0; round++) {
|
|
197
|
+
yield* eachRunner(ActorTest.use((test) => test.advance(settle)));
|
|
198
|
+
unsettled = yield* pending.pipe(Effect.repeat({
|
|
199
|
+
until: (count) => count === 0,
|
|
200
|
+
schedule: Schedule.spaced("100 millis"),
|
|
201
|
+
}), Effect.timeoutOrElse({ duration: "5 seconds", orElse: () => pending }));
|
|
202
|
+
}
|
|
203
|
+
if (unsettled > 0)
|
|
204
|
+
violations.push(`${unsettled} due or attempted outbox rows were never delivered`);
|
|
205
|
+
const left = (yield* eachRunner(clearFaults)).flat();
|
|
206
|
+
if (left.length > 0)
|
|
207
|
+
violations.push(`faults at ${left.join(", ")} were never reached`);
|
|
208
|
+
for (const step of steps) {
|
|
209
|
+
const [receipts] = yield* read(cluster.sql `
|
|
210
|
+
SELECT count(*)::integer AS count FROM actor_receipts
|
|
211
|
+
WHERE tenant_id = ${cluster.tenant} AND command_id = ${step.commandId}`);
|
|
212
|
+
if (receipts.count !== 1)
|
|
213
|
+
violations.push(`${step.label} (${step.commandId}) has ${receipts.count} receipts`);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
return yield* conclude({
|
|
217
|
+
seed: options.seed,
|
|
218
|
+
steps,
|
|
219
|
+
violations,
|
|
220
|
+
run,
|
|
221
|
+
cleanup: eachRunner(clearFaults).pipe(Effect.ignore),
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
/** Seeds pull requests run on a cluster: `0` and `1`. */
|
|
225
|
+
export const CLUSTER_SIMULATION_SEEDS = 2;
|
|
226
|
+
/** Seeds the nightly run covers on a cluster: about a minute each. */
|
|
227
|
+
export const NIGHTLY_CLUSTER_SIMULATION_SEEDS = 6;
|
|
228
|
+
/** Seeds pull requests run through a real primary failover, each on a primary and standby of its own: `0`. */
|
|
229
|
+
export const FAILOVER_SIMULATION_SEEDS = 1;
|
|
230
|
+
/** Seeds the nightly run puts through a real primary failover: under a minute each. */
|
|
231
|
+
export const NIGHTLY_FAILOVER_SIMULATION_SEEDS = 3;
|
|
232
|
+
const seedsOf = (countName, pullRequest, nightly) => Effect.gen(function* () {
|
|
233
|
+
const property = yield* Config.String("PROPERTY_SEED").pipe(Config.withDefault(""));
|
|
234
|
+
const random = property === "random";
|
|
235
|
+
const count = yield* Config.Int(countName).pipe(Config.withDefault(random ? nightly : pullRequest));
|
|
236
|
+
const configured = yield* Config.Int("SIMULATION_SEED_BASE").pipe(Config.option);
|
|
237
|
+
const base = Option.isSome(configured)
|
|
238
|
+
? configured.value
|
|
239
|
+
: random
|
|
240
|
+
? yield* Random.nextIntBetween(0, 2 ** 31 - 1 - count)
|
|
241
|
+
: 0;
|
|
242
|
+
if (random && Option.isNone(configured))
|
|
243
|
+
yield* Console.error(`${countName} seeds from ${base}`);
|
|
244
|
+
return Array.from({ length: count }, (_, index) => String(base + index));
|
|
245
|
+
}).pipe(Effect.orDie);
|
|
246
|
+
/**
|
|
247
|
+
* The seeds this run simulates on a cluster: `CLUSTER_SIMULATION_SEEDS` of
|
|
248
|
+
* them counted up from `SIMULATION_SEED_BASE`. A run whose `PROPERTY_SEED` is
|
|
249
|
+
* `random`, as the nightly run's is, defaults to
|
|
250
|
+
* `NIGHTLY_CLUSTER_SIMULATION_SEEDS` seeds from a base it draws and prints,
|
|
251
|
+
* so each night covers seeds no other night did; every other run defaults to
|
|
252
|
+
* `CLUSTER_SIMULATION_SEEDS` from 0. A failure names its seed; rerun it with
|
|
253
|
+
* `CLUSTER_SIMULATION_SEEDS=1 SIMULATION_SEED_BASE=<seed>`.
|
|
254
|
+
*/
|
|
255
|
+
export const clusterSimulationSeeds = seedsOf("CLUSTER_SIMULATION_SEEDS", CLUSTER_SIMULATION_SEEDS, NIGHTLY_CLUSTER_SIMULATION_SEEDS);
|
|
256
|
+
/** The seeds for the failover drill, chosen like `clusterSimulationSeeds` from `FAILOVER_SIMULATION_SEEDS`. */
|
|
257
|
+
export const failoverSimulationSeeds = seedsOf("FAILOVER_SIMULATION_SEEDS", FAILOVER_SIMULATION_SEEDS, NIGHTLY_FAILOVER_SIMULATION_SEEDS);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { Duration, Effect } from "effect";
|
|
2
|
+
import { SqlClient } from "effect/sql";
|
|
3
|
+
import { Actors } from "../index.ts";
|
|
4
|
+
import type { ActorTest } from "./actor-test.ts";
|
|
5
|
+
/**
|
|
6
|
+
* A fault `ActorTest.simulate` injects into one command:
|
|
7
|
+
* - `crashBeforeCommit`: the turn dies before COMMIT, so it rolls back and the handle retries.
|
|
8
|
+
* - `crashAfterCommit`: the turn commits and the reply is lost, so the retry reads the receipt.
|
|
9
|
+
* - `dropReply`: the caller discards the reply it got and sends the same command id again.
|
|
10
|
+
* - `relayCrash`: the next relay delivery dies before deleting its outbox row, so the row
|
|
11
|
+
* is redelivered once its claim lease ends. Drawn only for commands marked `relays`.
|
|
12
|
+
* - `clockSkew`: the framework clock jumps ahead of the database clock before the command.
|
|
13
|
+
*/
|
|
14
|
+
export type SimulationFault = "crashBeforeCommit" | "crashAfterCommit" | "dropReply" | "relayCrash" | "clockSkew";
|
|
15
|
+
export interface SimulationOptions {
|
|
16
|
+
/** Every draw, and so the whole fault schedule, follows from it. */
|
|
17
|
+
readonly seed: string;
|
|
18
|
+
readonly faults: ReadonlyArray<SimulationFault>;
|
|
19
|
+
/** Chance that a command gets a fault. Default 0.5. */
|
|
20
|
+
readonly faultRate?: number;
|
|
21
|
+
/** Largest `clockSkew` jump. Default 5 minutes. */
|
|
22
|
+
readonly maxSkew?: Duration.Input;
|
|
23
|
+
/** How far the clock moves to settle outstanding deliveries. Default 1 minute per round. */
|
|
24
|
+
readonly settle?: Duration.Input;
|
|
25
|
+
}
|
|
26
|
+
export interface SimulationStep {
|
|
27
|
+
readonly label: string;
|
|
28
|
+
readonly commandId: string;
|
|
29
|
+
readonly fault: SimulationFault | "none";
|
|
30
|
+
/** The `clockSkew` jump in milliseconds, 0 otherwise. */
|
|
31
|
+
readonly skewMs: number;
|
|
32
|
+
}
|
|
33
|
+
export interface SimulationReport {
|
|
34
|
+
readonly seed: string;
|
|
35
|
+
readonly steps: ReadonlyArray<SimulationStep>;
|
|
36
|
+
}
|
|
37
|
+
export interface Simulation {
|
|
38
|
+
readonly seed: string;
|
|
39
|
+
/**
|
|
40
|
+
* Runs one command under the seed's next fault, with a command id minted
|
|
41
|
+
* for it. `effect` must be a single command call, so it commits one receipt.
|
|
42
|
+
* `relays` marks a command whose turn stages an intent, so a relay crash
|
|
43
|
+
* drawn for it must be reached by that intent's delivery.
|
|
44
|
+
*/
|
|
45
|
+
readonly command: <A, E, R>(label: string, effect: Effect.Effect<A, E, R>, options?: {
|
|
46
|
+
readonly relays?: boolean;
|
|
47
|
+
}) => Effect.Effect<A, E, R>;
|
|
48
|
+
/** A seeded integer in `[min, max]`. */
|
|
49
|
+
readonly int: (min: number, max: number) => Effect.Effect<number>;
|
|
50
|
+
/** A seeded element of a non-empty list. */
|
|
51
|
+
readonly pick: <A>(values: readonly [A, ...Array<A>]) => Effect.Effect<A>;
|
|
52
|
+
}
|
|
53
|
+
/** A small seeded generator, so the schedule never depends on the runtime's own randomness. */
|
|
54
|
+
export declare const generator: (seed: string) => () => number;
|
|
55
|
+
/** Settling rounds before undelivered outbox rows count as lost. */
|
|
56
|
+
export declare const SETTLE_ROUNDS = 5;
|
|
57
|
+
/**
|
|
58
|
+
* Runs a simulation's `run`, then reports it: a defect or a violation dies
|
|
59
|
+
* with the seed and the schedule drawn, and `cleanup` runs however `run` ends.
|
|
60
|
+
*/
|
|
61
|
+
export declare const conclude: <Step extends {
|
|
62
|
+
readonly label: string;
|
|
63
|
+
readonly fault: string;
|
|
64
|
+
}, E, R>({ seed, steps, violations, run, cleanup, }: {
|
|
65
|
+
readonly seed: string;
|
|
66
|
+
readonly steps: ReadonlyArray<Step>;
|
|
67
|
+
readonly violations: ReadonlyArray<string>;
|
|
68
|
+
readonly run: Effect.Effect<void, E, R>;
|
|
69
|
+
readonly cleanup: Effect.Effect<unknown>;
|
|
70
|
+
}) => Effect.Effect<{
|
|
71
|
+
readonly seed: string;
|
|
72
|
+
readonly steps: ReadonlyArray<Step>;
|
|
73
|
+
}, never, R>;
|
|
74
|
+
/**
|
|
75
|
+
* Runs `program` against `test`'s runtime under a fault
|
|
76
|
+
* schedule drawn from `options.seed`, then settles the relay and checks that
|
|
77
|
+
* every command committed exactly one receipt and no due or attempted outbox
|
|
78
|
+
* row was left undelivered. Any failure dies with the seed, so rerunning that
|
|
79
|
+
* seed repeats the program's choices and the fault on each step; command ids
|
|
80
|
+
* are minted fresh on every run. A crashed delivery pushes its row's due time to the end of its claim lease, so an attempted row counts as in flight while an unattempted row that is not yet due is a timer the program scheduled.
|
|
81
|
+
*/
|
|
82
|
+
export declare const simulate: (test: ActorTest["Service"]) => <E, R>(options: SimulationOptions, program: (simulation: Simulation) => Effect.Effect<void, E, R>) => Effect.Effect<SimulationReport, never, R | Actors | SqlClient.SqlClient>;
|
|
83
|
+
/** Seeds pull requests run: `0` to `19`. */
|
|
84
|
+
export declare const SIMULATION_SEEDS = 20;
|
|
85
|
+
/**
|
|
86
|
+
* The seeds this run simulates: `SIMULATION_SEEDS` of them (default 20)
|
|
87
|
+
* counted up from `SIMULATION_SEED_BASE` (default 0), so a nightly run sets
|
|
88
|
+
* both and a failure names the seed to rerun.
|
|
89
|
+
*/
|
|
90
|
+
export declare const simulationSeeds: Effect.Effect<string[], never, never>;
|