@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,137 @@
|
|
|
1
|
+
import { Effect, Option, Schema } from "effect";
|
|
2
|
+
import { SqlClient } from "effect/sql";
|
|
3
|
+
import { VERSION_KEY } from "../../state/migration.js";
|
|
4
|
+
import { JOB_KEY_PREFIX } from "../../handles/intents.js";
|
|
5
|
+
import { decodeBytes, decodeText } from "../inspector/queries.js";
|
|
6
|
+
import { inReadOnlySnapshot } from "../database/snapshot.js";
|
|
7
|
+
import { TenantScope, tenantSettings } from "../database/tenancy.js";
|
|
8
|
+
import { databaseTime } from "../turn/admission.js";
|
|
9
|
+
import { SEED_FORMAT } from "./seed.js";
|
|
10
|
+
/** The most pending intents, and the most pending jobs, one export carries. */
|
|
11
|
+
export const MAX_EXPORT_ROWS = 10_000;
|
|
12
|
+
/**
|
|
13
|
+
* The actor cannot be exported faithfully: a stored value does not decode, or
|
|
14
|
+
* it holds more pending work than one export carries. `detail` names the row,
|
|
15
|
+
* never its contents.
|
|
16
|
+
*/
|
|
17
|
+
export class ExportRefused extends Schema.TaggedError()("ExportRefused", {
|
|
18
|
+
reason: Schema.Literals(["undecodable", "too_large"]),
|
|
19
|
+
detail: Schema.String,
|
|
20
|
+
}) {
|
|
21
|
+
}
|
|
22
|
+
const decodeVersion = Schema.decodeUnknownOption(Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)));
|
|
23
|
+
/**
|
|
24
|
+
* Runs `effect` in a read-only snapshot bound to `tenant`: as the runtime's
|
|
25
|
+
* tenant role when row-level security is on, so the policies confine every
|
|
26
|
+
* table read to the tenant, and by the `durable.tenant` setting otherwise.
|
|
27
|
+
*/
|
|
28
|
+
const tenantSnapshot = (tenant) => (effect) => Effect.gen(function* () {
|
|
29
|
+
const sql = yield* SqlClient.SqlClient;
|
|
30
|
+
const { role } = yield* TenantScope;
|
|
31
|
+
yield* role === undefined
|
|
32
|
+
? sql `SELECT set_config('durable.tenant', ${tenant}, true)`
|
|
33
|
+
: sql `SELECT ${tenantSettings({ sql, role, tenant })}`;
|
|
34
|
+
return yield* effect;
|
|
35
|
+
}).pipe(inReadOnlySnapshot);
|
|
36
|
+
/**
|
|
37
|
+
* Reads one actor's seed in a tenant-bound read-only snapshot: current
|
|
38
|
+
* state, the pending intents and timers, and the jobs not yet settled.
|
|
39
|
+
* Callers, credentials, receipts, event history, workflow executions, dead
|
|
40
|
+
* letters, owned-table rows, and blob entries are not carried; the seed counts
|
|
41
|
+
* them in `omitted`. Subscription cursors and connections are neither carried
|
|
42
|
+
* nor counted. A job whose attempt has been cancelled or has finally failed
|
|
43
|
+
* is not pending and is left out. It reads the runtime tables, not the
|
|
44
|
+
* inspection views, because the views do not show a cancelled job. `None`
|
|
45
|
+
* when the tenant has no such actor.
|
|
46
|
+
*/
|
|
47
|
+
export const exportActor = (page) => tenantSnapshot(page.tenant)(Effect.gen(function* () {
|
|
48
|
+
const sql = yield* SqlClient.SqlClient;
|
|
49
|
+
const [found] = yield* sql `
|
|
50
|
+
SELECT routing_key::text AS "routingKey", created FROM actor_generations
|
|
51
|
+
WHERE tenant_id = ${page.tenant} AND actor_type = ${page.actorType}
|
|
52
|
+
AND actor_id = ${page.actorId}`;
|
|
53
|
+
if (found === undefined)
|
|
54
|
+
return Option.none();
|
|
55
|
+
const { routingKey, created } = found;
|
|
56
|
+
const owned = sql `routing_key = ${routingKey}::int8 AND tenant_id = ${page.tenant}
|
|
57
|
+
AND actor_type = ${page.actorType} AND actor_id = ${page.actorId}`;
|
|
58
|
+
const exportedAtMs = yield* databaseTime;
|
|
59
|
+
const stored = yield* sql `
|
|
60
|
+
SELECT key, value FROM actor_state WHERE ${owned} ORDER BY key COLLATE "C"`;
|
|
61
|
+
const intents = yield* sql `
|
|
62
|
+
SELECT target_type AS "targetType", target_id AS "targetId", command, payload,
|
|
63
|
+
timer_key AS "timerKey", due_at_ms::float8 AS "dueAtMs"
|
|
64
|
+
FROM actor_outbox
|
|
65
|
+
WHERE ${owned} AND kind = 'intent'
|
|
66
|
+
ORDER BY due_at_ms, intent_id COLLATE "C" LIMIT ${MAX_EXPORT_ROWS + 1}`;
|
|
67
|
+
const jobs = yield* sql `
|
|
68
|
+
SELECT command AS job, payload, payload_version AS "payloadVersion",
|
|
69
|
+
timer_key AS "timerKey", due_at_ms::float8 AS "dueAtMs"
|
|
70
|
+
FROM actor_outbox
|
|
71
|
+
WHERE ${owned} AND kind = 'job' AND cancelled_at_ms IS NULL AND NOT final_failure
|
|
72
|
+
ORDER BY due_at_ms, intent_id COLLATE "C" LIMIT ${MAX_EXPORT_ROWS + 1}`;
|
|
73
|
+
if (intents.length > MAX_EXPORT_ROWS)
|
|
74
|
+
return yield* ExportRefused.make({ reason: "too_large", detail: "pending intents" });
|
|
75
|
+
if (jobs.length > MAX_EXPORT_ROWS)
|
|
76
|
+
return yield* ExportRefused.make({ reason: "too_large", detail: "pending jobs" });
|
|
77
|
+
const [counted] = yield* sql `
|
|
78
|
+
SELECT
|
|
79
|
+
(SELECT count(*)::int FROM actor_receipts WHERE ${owned}) AS receipts,
|
|
80
|
+
(SELECT count(*)::int FROM actor_events WHERE ${owned}) AS events,
|
|
81
|
+
(SELECT count(*)::int FROM actor_workflow_executions WHERE ${owned}) AS workflows,
|
|
82
|
+
(SELECT count(*)::int FROM actor_dead_letters WHERE ${owned}) AS "deadLetters",
|
|
83
|
+
(SELECT count(DISTINCT (blob, name))::int FROM actor_blobs WHERE ${owned})
|
|
84
|
+
+ (SELECT count(DISTINCT (blob, name))::int FROM actor_content_refs WHERE ${owned}) AS blobs`;
|
|
85
|
+
const tables = yield* sql `
|
|
86
|
+
SELECT table_schema AS schema, table_name AS "table" FROM actor_tables
|
|
87
|
+
WHERE actor_type = ${page.actorType}`;
|
|
88
|
+
let tableRows = 0;
|
|
89
|
+
for (const { schema, table } of tables) {
|
|
90
|
+
const [rows] = yield* sql `
|
|
91
|
+
SELECT count(*)::int AS count FROM ${sql(schema)}.${sql(table)}
|
|
92
|
+
WHERE routing_key = ${routingKey}::int8 AND tenant_id = ${page.tenant}
|
|
93
|
+
AND actor_id = ${page.actorId}`;
|
|
94
|
+
tableRows += rows.count;
|
|
95
|
+
}
|
|
96
|
+
const state = {};
|
|
97
|
+
let stateVersion = 0;
|
|
98
|
+
for (const row of stored) {
|
|
99
|
+
const decoded = decodeBytes(row.value);
|
|
100
|
+
if (decoded === null || "undecodable" in decoded)
|
|
101
|
+
return yield* ExportRefused.make({ reason: "undecodable", detail: `state ${row.key}` });
|
|
102
|
+
if (row.key !== VERSION_KEY)
|
|
103
|
+
state[row.key] = decoded.json;
|
|
104
|
+
else
|
|
105
|
+
stateVersion = Option.getOrElse(decodeVersion(decoded.json), () => 0);
|
|
106
|
+
}
|
|
107
|
+
const payloadOf = Effect.fnUntraced(function* (text, detail) {
|
|
108
|
+
const decoded = decodeText(text);
|
|
109
|
+
if (decoded === null || "undecodable" in decoded)
|
|
110
|
+
return yield* ExportRefused.make({ reason: "undecodable", detail });
|
|
111
|
+
return decoded.json;
|
|
112
|
+
});
|
|
113
|
+
const dueIn = (dueAtMs) => Math.max(0, Math.round(dueAtMs - exportedAtMs));
|
|
114
|
+
const seed = {
|
|
115
|
+
format: SEED_FORMAT,
|
|
116
|
+
actor: { type: page.actorType, id: page.actorId },
|
|
117
|
+
created,
|
|
118
|
+
stateVersion,
|
|
119
|
+
state,
|
|
120
|
+
intents: yield* Effect.forEach(intents, (row) => Effect.map(payloadOf(row.payload, `intent ${row.command}`), (payload) => ({
|
|
121
|
+
target: { actor: row.targetType, id: row.targetId },
|
|
122
|
+
command: row.command,
|
|
123
|
+
payload,
|
|
124
|
+
key: row.timerKey ?? undefined,
|
|
125
|
+
dueInMs: dueIn(row.dueAtMs),
|
|
126
|
+
}))),
|
|
127
|
+
jobs: yield* Effect.forEach(jobs, (row) => Effect.map(payloadOf(row.payload, `job ${row.job}`), (payload) => ({
|
|
128
|
+
job: row.job,
|
|
129
|
+
payload,
|
|
130
|
+
payloadVersion: row.payloadVersion,
|
|
131
|
+
key: row.timerKey?.replace(JOB_KEY_PREFIX, "") ?? undefined,
|
|
132
|
+
dueInMs: dueIn(row.dueAtMs),
|
|
133
|
+
}))),
|
|
134
|
+
omitted: { ...counted, tableRows },
|
|
135
|
+
};
|
|
136
|
+
return Option.some(seed);
|
|
137
|
+
}));
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Option, Schema } from "effect";
|
|
2
|
+
/** What an operator may do; each action is granted separately. */
|
|
3
|
+
export declare const OperatorAction: Schema.Literals<readonly ["inspect", "export", "receipts.read", "defects.read", "dead-letters.retry", "dead-letters.discard", "subscriptions.skip", "audit.read"]>;
|
|
4
|
+
/** One grantable operator action. */
|
|
5
|
+
export type OperatorAction = typeof OperatorAction.Type;
|
|
6
|
+
/**
|
|
7
|
+
* One action on one resource scope. `tenant` is a tenant id or `"*"` for
|
|
8
|
+
* every tenant; an omitted field matches any value, and `commandId` narrows
|
|
9
|
+
* `receipts.read` to one receipt.
|
|
10
|
+
*/
|
|
11
|
+
export declare const Capability: Schema.Struct<{
|
|
12
|
+
readonly action: Schema.Literals<readonly ["inspect", "export", "receipts.read", "defects.read", "dead-letters.retry", "dead-letters.discard", "subscriptions.skip", "audit.read"]>;
|
|
13
|
+
readonly tenant: Schema.NonEmptyString;
|
|
14
|
+
readonly actorType: Schema.optionalKey<Schema.NonEmptyString>;
|
|
15
|
+
readonly actorId: Schema.optionalKey<Schema.NonEmptyString>;
|
|
16
|
+
readonly commandId: Schema.optionalKey<Schema.NonEmptyString>;
|
|
17
|
+
}>;
|
|
18
|
+
/** One capability of a grant. */
|
|
19
|
+
export type Capability = typeof Capability.Type;
|
|
20
|
+
/** Who the operator is and every capability they hold. */
|
|
21
|
+
export declare const OperatorGrant: Schema.Struct<{
|
|
22
|
+
readonly operator: Schema.NonEmptyString;
|
|
23
|
+
readonly capabilities: Schema.$Array<Schema.Struct<{
|
|
24
|
+
readonly action: Schema.Literals<readonly ["inspect", "export", "receipts.read", "defects.read", "dead-letters.retry", "dead-letters.discard", "subscriptions.skip", "audit.read"]>;
|
|
25
|
+
readonly tenant: Schema.NonEmptyString;
|
|
26
|
+
readonly actorType: Schema.optionalKey<Schema.NonEmptyString>;
|
|
27
|
+
readonly actorId: Schema.optionalKey<Schema.NonEmptyString>;
|
|
28
|
+
readonly commandId: Schema.optionalKey<Schema.NonEmptyString>;
|
|
29
|
+
}>>;
|
|
30
|
+
}>;
|
|
31
|
+
/** An operator's identity and capabilities. */
|
|
32
|
+
export type OperatorGrant = typeof OperatorGrant.Type;
|
|
33
|
+
/** What one operator request touches; fields it doesn't name are tenant-wide. */
|
|
34
|
+
export interface Resource {
|
|
35
|
+
readonly tenant: string;
|
|
36
|
+
readonly actorType?: string | undefined;
|
|
37
|
+
readonly actorId?: string | undefined;
|
|
38
|
+
readonly commandId?: string | undefined;
|
|
39
|
+
}
|
|
40
|
+
/** The first capability of `grant` that allows `action` on `resource`. */
|
|
41
|
+
export declare const authorizing: ({ grant, action, resource, }: {
|
|
42
|
+
readonly grant: OperatorGrant;
|
|
43
|
+
readonly action: OperatorAction;
|
|
44
|
+
readonly resource: Resource;
|
|
45
|
+
}) => Option.Option<Capability>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Option, Schema } from "effect";
|
|
2
|
+
/** What an operator may do; each action is granted separately. */
|
|
3
|
+
export const OperatorAction = Schema.Literals([
|
|
4
|
+
"inspect",
|
|
5
|
+
"export",
|
|
6
|
+
"receipts.read",
|
|
7
|
+
"defects.read",
|
|
8
|
+
"dead-letters.retry",
|
|
9
|
+
"dead-letters.discard",
|
|
10
|
+
"subscriptions.skip",
|
|
11
|
+
"audit.read",
|
|
12
|
+
]);
|
|
13
|
+
/**
|
|
14
|
+
* One action on one resource scope. `tenant` is a tenant id or `"*"` for
|
|
15
|
+
* every tenant; an omitted field matches any value, and `commandId` narrows
|
|
16
|
+
* `receipts.read` to one receipt.
|
|
17
|
+
*/
|
|
18
|
+
export const Capability = Schema.Struct({
|
|
19
|
+
action: OperatorAction,
|
|
20
|
+
tenant: Schema.NonEmptyString,
|
|
21
|
+
actorType: Schema.optionalKey(Schema.NonEmptyString),
|
|
22
|
+
actorId: Schema.optionalKey(Schema.NonEmptyString),
|
|
23
|
+
commandId: Schema.optionalKey(Schema.NonEmptyString),
|
|
24
|
+
});
|
|
25
|
+
/** Who the operator is and every capability they hold. */
|
|
26
|
+
export const OperatorGrant = Schema.Struct({
|
|
27
|
+
operator: Schema.NonEmptyString,
|
|
28
|
+
capabilities: Schema.Array(Capability),
|
|
29
|
+
});
|
|
30
|
+
/**
|
|
31
|
+
* A capability field left open matches anything; a set one must name the
|
|
32
|
+
* resource's own value, so an actor-scoped grant never covers a tenant-wide read.
|
|
33
|
+
*/
|
|
34
|
+
const covers = (granted, requested) => granted === undefined || granted === requested;
|
|
35
|
+
/** The first capability of `grant` that allows `action` on `resource`. */
|
|
36
|
+
export const authorizing = ({ grant, action, resource, }) => Option.fromUndefinedOr(grant.capabilities.find((capability) => capability.action === action &&
|
|
37
|
+
(capability.tenant === "*" || capability.tenant === resource.tenant) &&
|
|
38
|
+
covers(capability.actorType, resource.actorType) &&
|
|
39
|
+
covers(capability.actorId, resource.actorId) &&
|
|
40
|
+
covers(capability.commandId, resource.commandId)));
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { Context, type Crypto, Effect, Option, Schema } from "effect";
|
|
2
|
+
import { SqlClient } from "effect/sql";
|
|
3
|
+
import type { RegisteredJob } from "../members.ts";
|
|
4
|
+
import * as Queries from "../inspector/queries.ts";
|
|
5
|
+
import { TenantScope } from "../database/tenancy.ts";
|
|
6
|
+
import { type Placement } from "../storage/codec.ts";
|
|
7
|
+
import { FrameworkClock } from "../turn/admission.ts";
|
|
8
|
+
import { OutboxRuntime } from "../turn/outbox.ts";
|
|
9
|
+
import { type ExportRefused } from "./export.ts";
|
|
10
|
+
import type { Seed } from "./seed.ts";
|
|
11
|
+
import { type AuditEntry, type AuditRecord } from "./audit.ts";
|
|
12
|
+
declare const OperatorNotFound_base: Schema.Class<OperatorNotFound, Schema.TaggedStruct<"OperatorNotFound", {}>, import("effect/Cause").YieldableError>;
|
|
13
|
+
/** The dead letter, receipt, or actor the request names does not exist. */
|
|
14
|
+
export declare class OperatorNotFound extends OperatorNotFound_base {
|
|
15
|
+
}
|
|
16
|
+
declare const ProviderOutcomeUnknown_base: Schema.Class<ProviderOutcomeUnknown, Schema.TaggedStruct<"ProviderOutcomeUnknown", {
|
|
17
|
+
readonly jobId: Schema.String;
|
|
18
|
+
}>, import("effect/Cause").YieldableError>;
|
|
19
|
+
/**
|
|
20
|
+
* The dead letter's last attempt may have applied the call. Retrying runs
|
|
21
|
+
* the provider call again under a new idempotency key, so the operator must
|
|
22
|
+
* state that they checked the provider first.
|
|
23
|
+
*/
|
|
24
|
+
export declare class ProviderOutcomeUnknown extends ProviderOutcomeUnknown_base {
|
|
25
|
+
}
|
|
26
|
+
declare const JobNotServed_base: Schema.Class<JobNotServed, Schema.TaggedStruct<"JobNotServed", {
|
|
27
|
+
readonly job: Schema.String;
|
|
28
|
+
}>, import("effect/Cause").YieldableError>;
|
|
29
|
+
/** This runner has no executor for the job, so it can't know how to queue a retry. */
|
|
30
|
+
export declare class JobNotServed extends JobNotServed_base {
|
|
31
|
+
}
|
|
32
|
+
/** Why a repair or operator read was refused. */
|
|
33
|
+
export type RepairError = OperatorNotFound | ProviderOutcomeUnknown | JobNotServed;
|
|
34
|
+
/** What an actor-scoped operator request names. */
|
|
35
|
+
export interface ActorTarget {
|
|
36
|
+
readonly tenant: string;
|
|
37
|
+
readonly actorType: string;
|
|
38
|
+
readonly actorId: string;
|
|
39
|
+
}
|
|
40
|
+
/** A stored outcome as an operator reads it: never re-executed. */
|
|
41
|
+
export interface ReceiptView {
|
|
42
|
+
readonly commandId: string;
|
|
43
|
+
readonly command: string;
|
|
44
|
+
readonly outcomeTag: string;
|
|
45
|
+
readonly outcome: Queries.Decoded | null;
|
|
46
|
+
readonly expiresAtMs: number;
|
|
47
|
+
}
|
|
48
|
+
declare const OperatorRuntime_base: Context.ServiceClass<OperatorRuntime, "@rikalabs/akter/runtime/operators/repair/OperatorRuntime", {
|
|
49
|
+
/** The actor type's recorded placement, or none when no runner registered it. */
|
|
50
|
+
readonly placement: (actorType: string) => Effect.Effect<Option.Option<Placement>>;
|
|
51
|
+
readonly inspect: (target: ActorTarget & {
|
|
52
|
+
readonly limit: number;
|
|
53
|
+
readonly outcomes: boolean;
|
|
54
|
+
}) => Effect.Effect<Option.Option<unknown>>;
|
|
55
|
+
readonly receipt: (target: ActorTarget & {
|
|
56
|
+
readonly commandId: string;
|
|
57
|
+
}) => Effect.Effect<Option.Option<ReceiptView>>;
|
|
58
|
+
/**
|
|
59
|
+
* One actor's seed, read in a single read-only snapshot; `None` when the
|
|
60
|
+
* tenant has no such actor.
|
|
61
|
+
*/
|
|
62
|
+
readonly exportSeed: (target: ActorTarget) => Effect.Effect<Option.Option<Seed>, ExportRefused>;
|
|
63
|
+
readonly retry: (request: {
|
|
64
|
+
readonly target: ActorTarget;
|
|
65
|
+
readonly jobId: string;
|
|
66
|
+
readonly providerChecked: boolean;
|
|
67
|
+
readonly audit: AuditEntry;
|
|
68
|
+
}) => Effect.Effect<{
|
|
69
|
+
readonly jobId: string;
|
|
70
|
+
}, RepairError>;
|
|
71
|
+
readonly discard: (request: {
|
|
72
|
+
readonly target: ActorTarget;
|
|
73
|
+
readonly jobId: string;
|
|
74
|
+
readonly audit: AuditEntry;
|
|
75
|
+
}) => Effect.Effect<void, RepairError>;
|
|
76
|
+
/**
|
|
77
|
+
* Skips a stuck subscription row's events through `through`: the row
|
|
78
|
+
* moves past them, and its subscriber is sent a marker for the range.
|
|
79
|
+
*/
|
|
80
|
+
readonly skip: (request: {
|
|
81
|
+
readonly target: ActorTarget;
|
|
82
|
+
readonly subscriberType: string;
|
|
83
|
+
readonly subscription: string;
|
|
84
|
+
readonly subscriberId: string;
|
|
85
|
+
readonly through: string;
|
|
86
|
+
readonly audit: AuditEntry;
|
|
87
|
+
}) => Effect.Effect<{
|
|
88
|
+
readonly through: string;
|
|
89
|
+
}, RepairError>;
|
|
90
|
+
/**
|
|
91
|
+
* A tenant's active subscription rows that have failed at least
|
|
92
|
+
* `minAttempts` deliveries in a row, most attempts first.
|
|
93
|
+
*/
|
|
94
|
+
readonly lagging: (page: {
|
|
95
|
+
readonly tenant: string;
|
|
96
|
+
readonly minAttempts: number;
|
|
97
|
+
readonly limit: number;
|
|
98
|
+
}) => Effect.Effect<ReadonlyArray<LaggingSubscription>>;
|
|
99
|
+
/** A tenant's newest audit rows, or every tenant's for `"*"`. */
|
|
100
|
+
readonly audit: (page: {
|
|
101
|
+
readonly tenant: string;
|
|
102
|
+
readonly limit: number;
|
|
103
|
+
}) => Effect.Effect<ReadonlyArray<AuditRecord>>;
|
|
104
|
+
/** Writes one audit row on its own; a read's row goes in before its answer. */
|
|
105
|
+
readonly record: (entry: AuditEntry, outcome: Schema.Json) => Effect.Effect<void>;
|
|
106
|
+
}>;
|
|
107
|
+
/**
|
|
108
|
+
* Operator reads and repairs that need the runtime's outbox and executors.
|
|
109
|
+
* Every repair writes its audit row in its own transaction.
|
|
110
|
+
*/
|
|
111
|
+
export declare class OperatorRuntime extends OperatorRuntime_base {
|
|
112
|
+
}
|
|
113
|
+
/** A subscription row whose deliveries keep failing, and how far behind its source it is. */
|
|
114
|
+
export interface LaggingSubscription {
|
|
115
|
+
readonly sourceType: string;
|
|
116
|
+
readonly sourceId: string;
|
|
117
|
+
readonly subscriberType: string;
|
|
118
|
+
readonly subscription: string;
|
|
119
|
+
readonly subscriberId: string;
|
|
120
|
+
readonly delivered: string;
|
|
121
|
+
readonly head: string;
|
|
122
|
+
readonly lag: string;
|
|
123
|
+
readonly attempts: number;
|
|
124
|
+
readonly lastError: string;
|
|
125
|
+
readonly dueAtMs: number | null;
|
|
126
|
+
}
|
|
127
|
+
/** What the runtime's clock and outbox references hold on this runner. */
|
|
128
|
+
type ReferenceOf<T> = T extends Context.Reference<infer S> ? S : never;
|
|
129
|
+
/**
|
|
130
|
+
* Builds the service over the runtime's SQL, crypto, clock, and outbox, and
|
|
131
|
+
* its job registrations, which say whether a retried job is capped.
|
|
132
|
+
*
|
|
133
|
+
* Repairs lock the dead letter they act on, so two repairs of it serialize and the
|
|
134
|
+
* second finds nothing. Without `receipts.read` an operator sees that a command
|
|
135
|
+
* ran, not what it returned. A retry is the operator's act and carries no end
|
|
136
|
+
* user's principal. The payload may hold customer data, so a discard's record
|
|
137
|
+
* keeps what failed, not what was sent.
|
|
138
|
+
*/
|
|
139
|
+
export declare const operatorRuntime: (deps: {
|
|
140
|
+
readonly services: Context.Context<SqlClient.SqlClient | Crypto.Crypto>;
|
|
141
|
+
readonly clock: ReferenceOf<typeof FrameworkClock>;
|
|
142
|
+
readonly outbox: ReferenceOf<typeof OutboxRuntime>;
|
|
143
|
+
readonly jobOf: (actorType: string, job: string) => RegisteredJob | undefined;
|
|
144
|
+
readonly wake: Effect.Effect<void>;
|
|
145
|
+
/** The tenant and adoption writer roles the operator's turns take, as the runtime's own turns do. */
|
|
146
|
+
readonly tenantScope: ReferenceOf<typeof TenantScope>;
|
|
147
|
+
}) => {
|
|
148
|
+
/** The actor type's recorded placement, or none when no runner registered it. */
|
|
149
|
+
readonly placement: (actorType: string) => Effect.Effect<Option.Option<Placement>>;
|
|
150
|
+
readonly inspect: (target: ActorTarget & {
|
|
151
|
+
readonly limit: number;
|
|
152
|
+
readonly outcomes: boolean;
|
|
153
|
+
}) => Effect.Effect<Option.Option<unknown>>;
|
|
154
|
+
readonly receipt: (target: ActorTarget & {
|
|
155
|
+
readonly commandId: string;
|
|
156
|
+
}) => Effect.Effect<Option.Option<ReceiptView>>;
|
|
157
|
+
/**
|
|
158
|
+
* One actor's seed, read in a single read-only snapshot; `None` when the
|
|
159
|
+
* tenant has no such actor.
|
|
160
|
+
*/
|
|
161
|
+
readonly exportSeed: (target: ActorTarget) => Effect.Effect<Option.Option<Seed>, ExportRefused>;
|
|
162
|
+
readonly retry: (request: {
|
|
163
|
+
readonly target: ActorTarget;
|
|
164
|
+
readonly jobId: string;
|
|
165
|
+
readonly providerChecked: boolean;
|
|
166
|
+
readonly audit: AuditEntry;
|
|
167
|
+
}) => Effect.Effect<{
|
|
168
|
+
readonly jobId: string;
|
|
169
|
+
}, RepairError>;
|
|
170
|
+
readonly discard: (request: {
|
|
171
|
+
readonly target: ActorTarget;
|
|
172
|
+
readonly jobId: string;
|
|
173
|
+
readonly audit: AuditEntry;
|
|
174
|
+
}) => Effect.Effect<void, RepairError>;
|
|
175
|
+
/**
|
|
176
|
+
* Skips a stuck subscription row's events through `through`: the row
|
|
177
|
+
* moves past them, and its subscriber is sent a marker for the range.
|
|
178
|
+
*/
|
|
179
|
+
readonly skip: (request: {
|
|
180
|
+
readonly target: ActorTarget;
|
|
181
|
+
readonly subscriberType: string;
|
|
182
|
+
readonly subscription: string;
|
|
183
|
+
readonly subscriberId: string;
|
|
184
|
+
readonly through: string;
|
|
185
|
+
readonly audit: AuditEntry;
|
|
186
|
+
}) => Effect.Effect<{
|
|
187
|
+
readonly through: string;
|
|
188
|
+
}, RepairError>;
|
|
189
|
+
/**
|
|
190
|
+
* A tenant's active subscription rows that have failed at least
|
|
191
|
+
* `minAttempts` deliveries in a row, most attempts first.
|
|
192
|
+
*/
|
|
193
|
+
readonly lagging: (page: {
|
|
194
|
+
readonly tenant: string;
|
|
195
|
+
readonly minAttempts: number;
|
|
196
|
+
readonly limit: number;
|
|
197
|
+
}) => Effect.Effect<ReadonlyArray<LaggingSubscription>>;
|
|
198
|
+
/** A tenant's newest audit rows, or every tenant's for `"*"`. */
|
|
199
|
+
readonly audit: (page: {
|
|
200
|
+
readonly tenant: string;
|
|
201
|
+
readonly limit: number;
|
|
202
|
+
}) => Effect.Effect<ReadonlyArray<AuditRecord>>;
|
|
203
|
+
/** Writes one audit row on its own; a read's row goes in before its answer. */
|
|
204
|
+
readonly record: (entry: AuditEntry, outcome: Schema.Json) => Effect.Effect<void>;
|
|
205
|
+
};
|
|
206
|
+
export {};
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { Context, Effect, Option, Schema } from "effect";
|
|
2
|
+
import { SqlClient, SqlError } from "effect/sql";
|
|
3
|
+
import { emptyOutbox } from "../../handles/intents.js";
|
|
4
|
+
import { ActorRef, System } from "../../identity/caller.js";
|
|
5
|
+
import * as Queries from "../inspector/queries.js";
|
|
6
|
+
import { TenantScope, withTenant } from "../database/tenancy.js";
|
|
7
|
+
import { routingKey } from "../storage/codec.js";
|
|
8
|
+
import { recordedPlacement } from "../storage/placements.js";
|
|
9
|
+
import { databaseTime, FrameworkClock } from "../turn/admission.js";
|
|
10
|
+
import { OutboxRuntime, outboxStatements } from "../turn/outbox.js";
|
|
11
|
+
import { exportActor } from "./export.js";
|
|
12
|
+
import { auditRoutingKey, listAudit, writeAudit, } from "./audit.js";
|
|
13
|
+
/** The dead letter, receipt, or actor the request names does not exist. */
|
|
14
|
+
export class OperatorNotFound extends Schema.TaggedError()("OperatorNotFound", {}) {
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The dead letter's last attempt may have applied the call. Retrying runs
|
|
18
|
+
* the provider call again under a new idempotency key, so the operator must
|
|
19
|
+
* state that they checked the provider first.
|
|
20
|
+
*/
|
|
21
|
+
export class ProviderOutcomeUnknown extends Schema.TaggedError()("ProviderOutcomeUnknown", { jobId: Schema.String }) {
|
|
22
|
+
}
|
|
23
|
+
/** This runner has no executor for the job, so it can't know how to queue a retry. */
|
|
24
|
+
export class JobNotServed extends Schema.TaggedError()("JobNotServed", {
|
|
25
|
+
job: Schema.String,
|
|
26
|
+
}) {
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Operator reads and repairs that need the runtime's outbox and executors.
|
|
30
|
+
* Every repair writes its audit row in its own transaction.
|
|
31
|
+
*/
|
|
32
|
+
export class OperatorRuntime extends Context.Service()("@rikalabs/akter/runtime/operators/repair/OperatorRuntime") {
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Builds the service over the runtime's SQL, crypto, clock, and outbox, and
|
|
36
|
+
* its job registrations, which say whether a retried job is capped.
|
|
37
|
+
*
|
|
38
|
+
* Repairs lock the dead letter they act on, so two repairs of it serialize and the
|
|
39
|
+
* second finds nothing. Without `receipts.read` an operator sees that a command
|
|
40
|
+
* ran, not what it returned. A retry is the operator's act and carries no end
|
|
41
|
+
* user's principal. The payload may hold customer data, so a discard's record
|
|
42
|
+
* keeps what failed, not what was sent.
|
|
43
|
+
*/
|
|
44
|
+
export const operatorRuntime = (deps) => {
|
|
45
|
+
const placement = (actorType) => recordedPlacement(actorType).pipe(Effect.map(Option.fromUndefinedOr), Effect.orDie, Effect.provideContext(deps.services));
|
|
46
|
+
const keyOf = (target) => Effect.flatMap(placement(target.actorType), (found) => Option.match(found, {
|
|
47
|
+
onNone: () => Effect.fail(OperatorNotFound.make({})),
|
|
48
|
+
onSome: (kind) => Effect.succeed(routingKey({
|
|
49
|
+
ref: { tenant: target.tenant, actor: target.actorType, id: target.actorId },
|
|
50
|
+
placement: kind,
|
|
51
|
+
})),
|
|
52
|
+
}));
|
|
53
|
+
const provided = (effect) => effect.pipe(Effect.catchIf(SqlError.isSqlError, Effect.die), Effect.provideService(FrameworkClock, deps.clock), Effect.provideService(OutboxRuntime, deps.outbox), Effect.provideService(TenantScope, deps.tenantScope), Effect.provideContext(deps.services));
|
|
54
|
+
/**
|
|
55
|
+
* Runs one repair of `target` in its own tenant transaction, and writes the
|
|
56
|
+
* repair's audit row, with the outcome it reports, in that same transaction.
|
|
57
|
+
*/
|
|
58
|
+
const auditedRepair = (target, audit, repair) => Effect.gen(function* () {
|
|
59
|
+
const key = yield* keyOf(target);
|
|
60
|
+
const sql = yield* SqlClient.SqlClient;
|
|
61
|
+
const { result } = yield* withTenant(target.tenant)(sql.withTransaction(Effect.tap(repair(key), ({ outcome }) => writeAudit({ entry: audit, key, outcome }))));
|
|
62
|
+
return result;
|
|
63
|
+
});
|
|
64
|
+
const lockLetter = (key, target, jobId) => Effect.gen(function* () {
|
|
65
|
+
const sql = yield* SqlClient.SqlClient;
|
|
66
|
+
const [letter] = yield* sql `
|
|
67
|
+
SELECT job, payload, payload_version AS "payloadVersion", attempts::int AS attempts, cause, ambiguous
|
|
68
|
+
FROM actor_dead_letters
|
|
69
|
+
WHERE routing_key = ${key} AND job_id = ${jobId} AND tenant_id = ${target.tenant}
|
|
70
|
+
AND actor_type = ${target.actorType} AND actor_id = ${target.actorId}
|
|
71
|
+
FOR UPDATE`;
|
|
72
|
+
if (letter === undefined)
|
|
73
|
+
return yield* OperatorNotFound.make({});
|
|
74
|
+
yield* sql `DELETE FROM actor_dead_letters WHERE routing_key = ${key} AND job_id = ${jobId}`;
|
|
75
|
+
return letter;
|
|
76
|
+
});
|
|
77
|
+
return OperatorRuntime.of({
|
|
78
|
+
placement,
|
|
79
|
+
inspect: ({ limit, outcomes, ...target }) => Queries.readOnly(target.tenant)(Queries.actor({ ...target, limit })).pipe(Effect.map(Option.map((page) => outcomes
|
|
80
|
+
? page
|
|
81
|
+
: {
|
|
82
|
+
...page,
|
|
83
|
+
receipts: page.receipts.map(({ outcome: _outcome, ...receipt }) => receipt),
|
|
84
|
+
})), Effect.orDie, provided),
|
|
85
|
+
receipt: ({ commandId, ...target }) => Effect.gen(function* () {
|
|
86
|
+
const key = yield* keyOf(target);
|
|
87
|
+
const sql = yield* SqlClient.SqlClient;
|
|
88
|
+
const [row] = yield* Queries.readOnly(target.tenant)(sql `SELECT command, outcome_tag, outcome, expires_at_ms::float8 AS expires_at_ms
|
|
89
|
+
FROM durable.receipts
|
|
90
|
+
WHERE routing_key = ${key} AND tenant_id = ${target.tenant}
|
|
91
|
+
AND actor_type = ${target.actorType} AND actor_id = ${target.actorId}
|
|
92
|
+
AND command_id = ${commandId}`);
|
|
93
|
+
return Option.map(Option.fromUndefinedOr(row), (found) => ({
|
|
94
|
+
commandId,
|
|
95
|
+
command: found.command,
|
|
96
|
+
outcomeTag: found.outcome_tag,
|
|
97
|
+
outcome: Queries.decodeText(found.outcome),
|
|
98
|
+
expiresAtMs: found.expires_at_ms,
|
|
99
|
+
}));
|
|
100
|
+
}).pipe(Effect.catchTag("OperatorNotFound", () => Effect.succeedNone), provided),
|
|
101
|
+
exportSeed: (target) => exportActor(target).pipe(Effect.catchIf(SqlError.isSqlError, Effect.die), provided),
|
|
102
|
+
retry: ({ target, jobId, providerChecked, audit }) => Effect.gen(function* () {
|
|
103
|
+
const ref = ActorRef.make({
|
|
104
|
+
tenant: target.tenant,
|
|
105
|
+
actor: target.actorType,
|
|
106
|
+
id: target.actorId,
|
|
107
|
+
});
|
|
108
|
+
const retried = yield* auditedRepair(target, audit, (key) => Effect.gen(function* () {
|
|
109
|
+
const letter = yield* lockLetter(key, target, jobId);
|
|
110
|
+
if (letter.ambiguous && !providerChecked)
|
|
111
|
+
return yield* ProviderOutcomeUnknown.make({ jobId });
|
|
112
|
+
const registered = deps.jobOf(target.actorType, letter.job);
|
|
113
|
+
if (registered === undefined)
|
|
114
|
+
return yield* JobNotServed.make({ job: letter.job });
|
|
115
|
+
const staged = yield* outboxStatements(key, ref, {
|
|
116
|
+
...emptyOutbox,
|
|
117
|
+
jobs: [
|
|
118
|
+
{
|
|
119
|
+
job: letter.job,
|
|
120
|
+
payload: letter.payload,
|
|
121
|
+
version: letter.payloadVersion,
|
|
122
|
+
caller: System.make({ source: "actor", ref }),
|
|
123
|
+
due: undefined,
|
|
124
|
+
key: undefined,
|
|
125
|
+
capped: registered.perActor !== undefined,
|
|
126
|
+
},
|
|
127
|
+
],
|
|
128
|
+
}, databaseTime);
|
|
129
|
+
for (const statement of staged.statements)
|
|
130
|
+
yield* statement;
|
|
131
|
+
const retriedId = staged.jobIds[0];
|
|
132
|
+
return {
|
|
133
|
+
result: { jobId: retriedId },
|
|
134
|
+
outcome: {
|
|
135
|
+
retried: jobId,
|
|
136
|
+
jobId: retriedId,
|
|
137
|
+
job: letter.job,
|
|
138
|
+
attempts: letter.attempts,
|
|
139
|
+
ambiguous: letter.ambiguous,
|
|
140
|
+
providerChecked,
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
}));
|
|
144
|
+
yield* deps.wake;
|
|
145
|
+
return retried;
|
|
146
|
+
}).pipe(provided),
|
|
147
|
+
discard: ({ target, jobId, audit }) => auditedRepair(target, audit, (key) => Effect.map(lockLetter(key, target, jobId), (letter) => ({
|
|
148
|
+
result: undefined,
|
|
149
|
+
outcome: {
|
|
150
|
+
discarded: jobId,
|
|
151
|
+
job: letter.job,
|
|
152
|
+
attempts: letter.attempts,
|
|
153
|
+
ambiguous: letter.ambiguous,
|
|
154
|
+
cause: letter.cause,
|
|
155
|
+
},
|
|
156
|
+
}))).pipe(provided),
|
|
157
|
+
skip: ({ target, subscriberType, subscription, subscriberId, through, audit }) => Effect.gen(function* () {
|
|
158
|
+
yield* auditedRepair(target, audit, (key) => Effect.gen(function* () {
|
|
159
|
+
const sql = yield* SqlClient.SqlClient;
|
|
160
|
+
const now = yield* databaseTime;
|
|
161
|
+
const [skipped] = yield* sql `
|
|
162
|
+
UPDATE actor_subscriptions s
|
|
163
|
+
SET gap_at_ms = ${now}, gap_through = ${BigInt(through)}, attempts = 0,
|
|
164
|
+
last_error = NULL, due_at_ms = ${now}
|
|
165
|
+
FROM (SELECT delivered, last_error FROM actor_subscriptions
|
|
166
|
+
WHERE routing_key = ${key} AND tenant_id = ${target.tenant}
|
|
167
|
+
AND source_type = ${target.actorType} AND source_id = ${target.actorId}
|
|
168
|
+
AND subscriber_type = ${subscriberType} AND subscription = ${subscription}
|
|
169
|
+
AND subscriber_id = ${subscriberId}
|
|
170
|
+
AND active AND last_error IS NOT NULL AND delivered < ${BigInt(through)}
|
|
171
|
+
FOR UPDATE) old
|
|
172
|
+
WHERE s.routing_key = ${key} AND s.tenant_id = ${target.tenant}
|
|
173
|
+
AND s.source_type = ${target.actorType} AND s.source_id = ${target.actorId}
|
|
174
|
+
AND s.subscriber_type = ${subscriberType} AND s.subscription = ${subscription}
|
|
175
|
+
AND s.subscriber_id = ${subscriberId}
|
|
176
|
+
AND ${BigInt(through)} <= (SELECT g.event_sequence FROM actor_generations g
|
|
177
|
+
WHERE g.routing_key = ${key} AND g.tenant_id = ${target.tenant}
|
|
178
|
+
AND g.actor_type = ${target.actorType} AND g.actor_id = ${target.actorId})
|
|
179
|
+
RETURNING old.delivered::text AS delivered, old.last_error AS "lastError"`;
|
|
180
|
+
if (skipped === undefined)
|
|
181
|
+
return yield* OperatorNotFound.make({});
|
|
182
|
+
return {
|
|
183
|
+
result: undefined,
|
|
184
|
+
outcome: {
|
|
185
|
+
subscriber: `${subscriberType}.${subscription}/${subscriberId}`,
|
|
186
|
+
after: skipped.delivered,
|
|
187
|
+
through,
|
|
188
|
+
lastError: skipped.lastError,
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
}));
|
|
192
|
+
yield* deps.wake;
|
|
193
|
+
return { through };
|
|
194
|
+
}).pipe(provided),
|
|
195
|
+
lagging: ({ tenant, minAttempts, limit }) => Queries.readOnly(tenant)(Effect.gen(function* () {
|
|
196
|
+
const sql = yield* SqlClient.SqlClient;
|
|
197
|
+
return yield* sql `
|
|
198
|
+
SELECT s.source_type AS "sourceType", s.source_id AS "sourceId",
|
|
199
|
+
s.subscriber_type AS "subscriberType", s.subscription,
|
|
200
|
+
s.subscriber_id AS "subscriberId", s.delivered::text AS delivered,
|
|
201
|
+
g.event_sequence::text AS head, (g.event_sequence - s.delivered)::text AS lag,
|
|
202
|
+
s.attempts::int AS attempts, s.last_error AS "lastError",
|
|
203
|
+
s.due_at_ms::float8 AS "dueAtMs"
|
|
204
|
+
FROM actor_subscriptions s
|
|
205
|
+
JOIN actor_generations g ON g.routing_key = s.routing_key
|
|
206
|
+
AND g.tenant_id = s.tenant_id AND g.actor_type = s.source_type
|
|
207
|
+
AND g.actor_id = s.source_id
|
|
208
|
+
WHERE s.tenant_id = ${tenant} AND s.active AND s.last_error IS NOT NULL
|
|
209
|
+
AND s.attempts >= ${minAttempts}
|
|
210
|
+
ORDER BY s.attempts DESC, g.event_sequence - s.delivered DESC,
|
|
211
|
+
s.source_type COLLATE "C", s.source_id COLLATE "C",
|
|
212
|
+
s.subscriber_type COLLATE "C", s.subscription COLLATE "C",
|
|
213
|
+
s.subscriber_id COLLATE "C"
|
|
214
|
+
LIMIT ${limit}`;
|
|
215
|
+
})).pipe(provided, Effect.orDie),
|
|
216
|
+
audit: (page) => Queries.readOnly(page.tenant)(listAudit(page)).pipe(provided, Effect.orDie),
|
|
217
|
+
record: (entry, outcome) => Effect.gen(function* () {
|
|
218
|
+
const found = entry.actorType === undefined ? Option.none() : yield* placement(entry.actorType);
|
|
219
|
+
yield* writeAudit({
|
|
220
|
+
entry,
|
|
221
|
+
key: auditRoutingKey({ entry, placement: Option.getOrUndefined(found) }),
|
|
222
|
+
outcome,
|
|
223
|
+
});
|
|
224
|
+
}).pipe(provided, Effect.orDie),
|
|
225
|
+
});
|
|
226
|
+
};
|