@rikalabs/akter 0.1.0-alpha.0 → 0.1.0-alpha.3
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 +46 -3
- package/README.md +2 -2
- package/dist/actor/definition.d.ts +13 -9
- package/dist/actor/descriptor.d.ts +2 -2
- package/dist/actor/descriptor.js +4 -4
- package/dist/client/calls.js +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js +1 -1
- package/dist/errors/actor.d.ts +12 -42
- package/dist/errors/actor.js +13 -42
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/members/payload.d.ts +1 -1
- package/dist/protocol/inspection.d.ts +221 -1
- package/dist/protocol/inspection.js +151 -2
- package/dist/protocol/wire.d.ts +6 -49
- package/dist/protocol/wire.js +1 -10
- package/dist/runtime/actors.d.ts +3 -0
- package/dist/runtime/adoption/backfill.js +1 -1
- package/dist/runtime/adoption/enforce.js +2 -2
- package/dist/runtime/adoption/observe.js +1 -1
- package/dist/runtime/adoption/plan.d.ts +1 -1
- package/dist/runtime/adoption/startup.js +1 -1
- package/dist/runtime/adoption/status.d.ts +1 -1
- package/dist/runtime/app.d.ts +65 -0
- package/dist/runtime/app.js +38 -0
- package/dist/runtime/connections/holder.d.ts +11 -1
- package/dist/runtime/connections/holder.js +8 -4
- package/dist/runtime/connections/streams.d.ts +4 -4
- package/dist/runtime/content/store.js +15 -11
- package/dist/runtime/database/bounded.d.ts +4 -18
- package/dist/runtime/database/bounded.js +36 -22
- package/dist/runtime/database/coordination.d.ts +12 -3
- package/dist/runtime/database/coordination.js +29 -36
- package/dist/runtime/database/migrations.d.ts +61 -29
- package/dist/runtime/database/migrations.js +375 -139
- package/dist/runtime/database/replica.d.ts +4 -1
- package/dist/runtime/database/replica.js +4 -1
- package/dist/runtime/database/schema.d.ts +13 -0
- package/dist/runtime/database/schema.js +13 -0
- package/dist/runtime/database/shards.d.ts +31 -13
- package/dist/runtime/database/shards.js +38 -26
- package/dist/runtime/entity/register.d.ts +8 -1
- package/dist/runtime/entity/register.js +58 -7
- package/dist/runtime/fleet/checks.js +4 -4
- package/dist/runtime/fleet/maintainer.d.ts +1 -1
- package/dist/runtime/fleet/maintainer.js +1 -1
- package/dist/runtime/index.d.ts +2 -0
- package/dist/runtime/index.js +1 -0
- package/dist/runtime/inspector/layer.d.ts +20 -0
- package/dist/runtime/inspector/layer.js +224 -5
- package/dist/runtime/inspector/queries.d.ts +54 -8
- package/dist/runtime/inspector/queries.js +84 -15
- package/dist/runtime/layer.d.ts +48 -39
- package/dist/runtime/layer.js +124 -56
- package/dist/runtime/operators/audit.d.ts +3 -0
- package/dist/runtime/operators/audit.js +6 -2
- package/dist/runtime/operators/repair.js +30 -10
- package/dist/runtime/operators/seed.js +4 -2
- package/dist/runtime/payloads/versions.d.ts +4 -4
- package/dist/runtime/payloads/versions.js +24 -15
- package/dist/runtime/queries.js +4 -2
- package/dist/runtime/registration.d.ts +5 -2
- package/dist/runtime/registration.js +3 -3
- package/dist/runtime/runner.d.ts +12 -0
- package/dist/runtime/runner.js +12 -0
- package/dist/runtime/storage/codec.d.ts +19 -7
- package/dist/runtime/storage/codec.js +23 -7
- package/dist/runtime/storage/placements.d.ts +6 -1
- package/dist/runtime/storage/placements.js +98 -6
- package/dist/runtime/storage/retention.d.ts +6 -0
- package/dist/runtime/storage/retention.js +25 -13
- package/dist/runtime/subscriptions/relay.js +47 -44
- package/dist/runtime/subscriptions/storage.d.ts +3 -2
- package/dist/runtime/subscriptions/storage.js +9 -6
- package/dist/runtime/telemetry/live.d.ts +255 -0
- package/dist/runtime/telemetry/live.js +540 -0
- package/dist/runtime/telemetry/metrics.d.ts +2 -0
- package/dist/runtime/telemetry/metrics.js +4 -1
- package/dist/runtime/telemetry/sampler.js +33 -13
- package/dist/runtime/telemetry/spans.d.ts +1 -1
- package/dist/runtime/telemetry/spans.js +1 -1
- package/dist/runtime/topology/locks.d.ts +6 -3
- package/dist/runtime/topology/locks.js +27 -4
- package/dist/runtime/turn/execute.d.ts +2 -0
- package/dist/runtime/turn/execute.js +5 -2
- package/dist/runtime/turn/pipeline.d.ts +5 -12
- package/dist/runtime/turn/pipeline.js +11 -11
- package/dist/runtime/turn/relay.d.ts +13 -3
- package/dist/runtime/turn/relay.js +27 -14
- package/dist/runtime/turn/rows.js +4 -4
- package/dist/runtime/workflows/compatibility.d.ts +1 -1
- package/dist/runtime/workflows/compatibility.js +85 -31
- package/dist/runtime/workflows/engine.js +20 -17
- package/dist/serve/layer.js +3 -2
- package/dist/tables/owned.d.ts +1 -1
- package/dist/tables/owned.js +1 -1
- package/dist/testing/actor-test.d.ts +2 -24
- package/dist/testing/actor-test.js +1 -27
- package/dist/testing/index.d.ts +0 -12
- package/dist/testing/index.js +0 -6
- package/package.json +1 -1
- package/dist/runtime/database/neki/migrations.d.ts +0 -31
- package/dist/runtime/database/neki/migrations.js +0 -276
- package/dist/runtime/database/neki/session.d.ts +0 -23
- package/dist/runtime/database/neki/session.js +0 -31
- package/dist/testing/cluster.d.ts +0 -93
- package/dist/testing/cluster.js +0 -296
- package/dist/testing/conformance/access.d.ts +0 -5
- package/dist/testing/conformance/access.js +0 -531
- package/dist/testing/conformance/admission.d.ts +0 -11
- package/dist/testing/conformance/admission.js +0 -182
- package/dist/testing/conformance/adoption.d.ts +0 -2
- package/dist/testing/conformance/adoption.js +0 -1019
- package/dist/testing/conformance/assertions.d.ts +0 -202
- package/dist/testing/conformance/assertions.js +0 -849
- package/dist/testing/conformance/batches.d.ts +0 -41
- package/dist/testing/conformance/batches.js +0 -388
- package/dist/testing/conformance/blobs.d.ts +0 -14
- package/dist/testing/conformance/blobs.js +0 -405
- package/dist/testing/conformance/capacity.d.ts +0 -8
- package/dist/testing/conformance/capacity.js +0 -433
- package/dist/testing/conformance/client.d.ts +0 -5
- package/dist/testing/conformance/client.js +0 -719
- package/dist/testing/conformance/cold-serve.d.ts +0 -16
- package/dist/testing/conformance/cold-serve.js +0 -254
- package/dist/testing/conformance/connections/actors.d.ts +0 -1143
- package/dist/testing/conformance/connections/actors.js +0 -180
- package/dist/testing/conformance/connections/harness.d.ts +0 -1754
- package/dist/testing/conformance/connections/harness.js +0 -142
- package/dist/testing/conformance/connections/holders.d.ts +0 -4
- package/dist/testing/conformance/connections/holders.js +0 -165
- package/dist/testing/conformance/connections/lifecycle.d.ts +0 -4
- package/dist/testing/conformance/connections/lifecycle.js +0 -113
- package/dist/testing/conformance/connections/limits.d.ts +0 -4
- package/dist/testing/conformance/connections/limits.js +0 -127
- package/dist/testing/conformance/connections/reauthorization.d.ts +0 -4
- package/dist/testing/conformance/connections/reauthorization.js +0 -170
- package/dist/testing/conformance/connections/resync.d.ts +0 -4
- package/dist/testing/conformance/connections/resync.js +0 -360
- package/dist/testing/conformance/connections/takeover.d.ts +0 -4
- package/dist/testing/conformance/connections/takeover.js +0 -287
- package/dist/testing/conformance/connections.d.ts +0 -4
- package/dist/testing/conformance/connections.js +0 -15
- package/dist/testing/conformance/content-blobs.d.ts +0 -16
- package/dist/testing/conformance/content-blobs.js +0 -534
- package/dist/testing/conformance/counter.d.ts +0 -16
- package/dist/testing/conformance/counter.js +0 -813
- package/dist/testing/conformance/cron.d.ts +0 -5
- package/dist/testing/conformance/cron.js +0 -665
- package/dist/testing/conformance/drain.d.ts +0 -26
- package/dist/testing/conformance/drain.js +0 -540
- package/dist/testing/conformance/effect-control.d.ts +0 -38
- package/dist/testing/conformance/effect-control.js +0 -1059
- package/dist/testing/conformance/effects.d.ts +0 -23
- package/dist/testing/conformance/effects.js +0 -432
- package/dist/testing/conformance/events.d.ts +0 -28
- package/dist/testing/conformance/events.js +0 -335
- package/dist/testing/conformance/export.d.ts +0 -2
- package/dist/testing/conformance/export.js +0 -368
- package/dist/testing/conformance/fleet.d.ts +0 -444
- package/dist/testing/conformance/fleet.js +0 -1009
- package/dist/testing/conformance/groups.d.ts +0 -7
- package/dist/testing/conformance/groups.js +0 -353
- package/dist/testing/conformance/heap.d.ts +0 -3
- package/dist/testing/conformance/heap.js +0 -149
- package/dist/testing/conformance/http.d.ts +0 -2809
- package/dist/testing/conformance/http.js +0 -1234
- package/dist/testing/conformance/inspection-views.d.ts +0 -8
- package/dist/testing/conformance/inspection-views.js +0 -272
- package/dist/testing/conformance/inspector.d.ts +0 -7
- package/dist/testing/conformance/inspector.js +0 -650
- package/dist/testing/conformance/mint.d.ts +0 -58
- package/dist/testing/conformance/mint.js +0 -692
- package/dist/testing/conformance/multi-runner.d.ts +0 -8
- package/dist/testing/conformance/multi-runner.js +0 -403
- package/dist/testing/conformance/neki/plan.d.ts +0 -19
- package/dist/testing/conformance/neki/plan.js +0 -30
- package/dist/testing/conformance/observability.d.ts +0 -3
- package/dist/testing/conformance/observability.js +0 -343
- package/dist/testing/conformance/offline.d.ts +0 -4
- package/dist/testing/conformance/offline.js +0 -474
- package/dist/testing/conformance/operator-harness.d.ts +0 -57
- package/dist/testing/conformance/operator-harness.js +0 -78
- package/dist/testing/conformance/operator.d.ts +0 -3
- package/dist/testing/conformance/operator.js +0 -379
- package/dist/testing/conformance/outbox-cross-shard.d.ts +0 -14
- package/dist/testing/conformance/outbox-cross-shard.js +0 -160
- package/dist/testing/conformance/outbox.d.ts +0 -36
- package/dist/testing/conformance/outbox.js +0 -437
- package/dist/testing/conformance/payload-migrations.d.ts +0 -3
- package/dist/testing/conformance/payload-migrations.js +0 -612
- package/dist/testing/conformance/pipeline.d.ts +0 -3
- package/dist/testing/conformance/pipeline.js +0 -1040
- package/dist/testing/conformance/placement.d.ts +0 -22
- package/dist/testing/conformance/placement.js +0 -539
- package/dist/testing/conformance/platform.d.ts +0 -40
- package/dist/testing/conformance/platform.js +0 -101
- package/dist/testing/conformance/progress.d.ts +0 -39
- package/dist/testing/conformance/progress.js +0 -666
- package/dist/testing/conformance/properties.d.ts +0 -6
- package/dist/testing/conformance/properties.js +0 -295
- package/dist/testing/conformance/protocols.d.ts +0 -4
- package/dist/testing/conformance/protocols.js +0 -618
- package/dist/testing/conformance/provider/advertise.d.ts +0 -21
- package/dist/testing/conformance/provider/advertise.js +0 -44
- package/dist/testing/conformance/read-your-writes.d.ts +0 -20
- package/dist/testing/conformance/read-your-writes.js +0 -192
- package/dist/testing/conformance/reducers.d.ts +0 -8
- package/dist/testing/conformance/reducers.js +0 -258
- package/dist/testing/conformance/relay.d.ts +0 -42
- package/dist/testing/conformance/relay.js +0 -1115
- package/dist/testing/conformance/restore.d.ts +0 -43
- package/dist/testing/conformance/restore.js +0 -341
- package/dist/testing/conformance/retention.d.ts +0 -14
- package/dist/testing/conformance/retention.js +0 -463
- package/dist/testing/conformance/rls.d.ts +0 -24
- package/dist/testing/conformance/rls.js +0 -576
- package/dist/testing/conformance/simulation.d.ts +0 -31
- package/dist/testing/conformance/simulation.js +0 -167
- package/dist/testing/conformance/single-shard.d.ts +0 -2
- package/dist/testing/conformance/single-shard.js +0 -125
- package/dist/testing/conformance/singleton.d.ts +0 -3
- package/dist/testing/conformance/singleton.js +0 -293
- package/dist/testing/conformance/statements.d.ts +0 -60
- package/dist/testing/conformance/statements.js +0 -108
- package/dist/testing/conformance/streams.d.ts +0 -7
- package/dist/testing/conformance/streams.js +0 -280
- package/dist/testing/conformance/subscriptions/access.d.ts +0 -4
- package/dist/testing/conformance/subscriptions/access.js +0 -98
- package/dist/testing/conformance/subscriptions/actors.d.ts +0 -4910
- package/dist/testing/conformance/subscriptions/actors.js +0 -372
- package/dist/testing/conformance/subscriptions/cluster.d.ts +0 -4
- package/dist/testing/conformance/subscriptions/cluster.js +0 -89
- package/dist/testing/conformance/subscriptions/delivery.d.ts +0 -4
- package/dist/testing/conformance/subscriptions/delivery.js +0 -253
- package/dist/testing/conformance/subscriptions/deploys.d.ts +0 -4
- package/dist/testing/conformance/subscriptions/deploys.js +0 -162
- package/dist/testing/conformance/subscriptions/epochs.d.ts +0 -4
- package/dist/testing/conformance/subscriptions/epochs.js +0 -169
- package/dist/testing/conformance/subscriptions/failures.d.ts +0 -4
- package/dist/testing/conformance/subscriptions/failures.js +0 -108
- package/dist/testing/conformance/subscriptions/feeds.d.ts +0 -4
- package/dist/testing/conformance/subscriptions/feeds.js +0 -218
- package/dist/testing/conformance/subscriptions/harness.d.ts +0 -124
- package/dist/testing/conformance/subscriptions/harness.js +0 -143
- package/dist/testing/conformance/subscriptions/operator.d.ts +0 -4
- package/dist/testing/conformance/subscriptions/operator.js +0 -128
- package/dist/testing/conformance/subscriptions/retention.d.ts +0 -4
- package/dist/testing/conformance/subscriptions/retention.js +0 -288
- package/dist/testing/conformance/subscriptions/routing.d.ts +0 -4
- package/dist/testing/conformance/subscriptions/routing.js +0 -179
- package/dist/testing/conformance/subscriptions.d.ts +0 -4
- package/dist/testing/conformance/subscriptions.js +0 -19
- package/dist/testing/conformance/tables.d.ts +0 -125
- package/dist/testing/conformance/tables.js +0 -664
- package/dist/testing/conformance/transports/actors.d.ts +0 -1907
- package/dist/testing/conformance/transports/actors.js +0 -163
- package/dist/testing/conformance/transports/client.d.ts +0 -3
- package/dist/testing/conformance/transports/client.js +0 -237
- package/dist/testing/conformance/transports/feeds.d.ts +0 -3
- package/dist/testing/conformance/transports/feeds.js +0 -232
- package/dist/testing/conformance/transports/harness.d.ts +0 -93
- package/dist/testing/conformance/transports/harness.js +0 -84
- package/dist/testing/conformance/transports/streams.d.ts +0 -3
- package/dist/testing/conformance/transports/streams.js +0 -96
- package/dist/testing/conformance/transports/websocket.d.ts +0 -3
- package/dist/testing/conformance/transports/websocket.js +0 -384
- package/dist/testing/conformance/transports/wire.d.ts +0 -141
- package/dist/testing/conformance/transports/wire.js +0 -204
- package/dist/testing/conformance/transports.d.ts +0 -3
- package/dist/testing/conformance/transports.js +0 -11
- package/dist/testing/conformance/watch.d.ts +0 -59
- package/dist/testing/conformance/watch.js +0 -879
- package/dist/testing/conformance/workflow-engine.d.ts +0 -97
- package/dist/testing/conformance/workflow-engine.js +0 -253
- package/dist/testing/conformance/workflow-versions.d.ts +0 -3
- package/dist/testing/conformance/workflow-versions.js +0 -545
- package/dist/testing/conformance/workflows/access.d.ts +0 -4
- package/dist/testing/conformance/workflows/access.js +0 -147
- package/dist/testing/conformance/workflows/actors.d.ts +0 -2317
- package/dist/testing/conformance/workflows/actors.js +0 -305
- package/dist/testing/conformance/workflows/basics.d.ts +0 -4
- package/dist/testing/conformance/workflows/basics.js +0 -144
- package/dist/testing/conformance/workflows/engine.d.ts +0 -4
- package/dist/testing/conformance/workflows/engine.js +0 -80
- package/dist/testing/conformance/workflows/guards.d.ts +0 -4
- package/dist/testing/conformance/workflows/guards.js +0 -172
- package/dist/testing/conformance/workflows/harness.d.ts +0 -14
- package/dist/testing/conformance/workflows/harness.js +0 -44
- package/dist/testing/conformance/workflows/recovery.d.ts +0 -4
- package/dist/testing/conformance/workflows/recovery.js +0 -181
- package/dist/testing/conformance/workflows/starts.d.ts +0 -4
- package/dist/testing/conformance/workflows/starts.js +0 -57
- package/dist/testing/conformance/workflows/suspension.d.ts +0 -4
- package/dist/testing/conformance/workflows/suspension.js +0 -106
- package/dist/testing/conformance/workflows/waits.d.ts +0 -4
- package/dist/testing/conformance/workflows/waits.js +0 -284
- package/dist/testing/conformance/workflows.d.ts +0 -4
- package/dist/testing/conformance/workflows.js +0 -19
- package/dist/testing/conformance.d.ts +0 -330
- package/dist/testing/conformance.js +0 -364
- package/dist/testing/foundation.d.ts +0 -41
- package/dist/testing/foundation.js +0 -517
- package/dist/testing/simulate-cluster.d.ts +0 -112
- package/dist/testing/simulate-cluster.js +0 -257
- package/dist/testing/simulate.d.ts +0 -90
- package/dist/testing/simulate.js +0 -127
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { dual } from "effect/Function";
|
|
3
|
+
import { SqlClient } from "effect/sql";
|
|
4
|
+
/**
|
|
5
|
+
* Runs an application's own schema setup on the ambient `SqlClient` while
|
|
6
|
+
* holding advisory lock `lock`, so processes starting together apply it one
|
|
7
|
+
* at a time. The lock and every statement share one transaction, so a failed
|
|
8
|
+
* setup rolls back together and releases its lock.
|
|
9
|
+
*/
|
|
10
|
+
export const schemaChange = dual(2, (effect, lock) => Effect.gen(function* () {
|
|
11
|
+
const sql = yield* SqlClient.SqlClient;
|
|
12
|
+
return yield* sql.withTransaction(Effect.andThen(sql `SELECT pg_advisory_xact_lock(${lock})`, effect));
|
|
13
|
+
}));
|
|
@@ -1,21 +1,39 @@
|
|
|
1
1
|
import { Context, Effect } from "effect";
|
|
2
|
-
import { SqlClient } from "effect/sql";
|
|
3
|
-
/** One inclusive
|
|
2
|
+
import type { SqlClient } from "effect/sql";
|
|
3
|
+
/** One inclusive scheduling range, independent of actor compute ownership. */
|
|
4
4
|
export interface BucketRange {
|
|
5
5
|
readonly first: number;
|
|
6
6
|
readonly last: number;
|
|
7
|
-
/** Neki's shard UID; absent on an ordinary single database. */
|
|
8
|
-
readonly shard?: string | undefined;
|
|
9
7
|
}
|
|
10
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* Bucket ranges on one database. The default covers the whole key space;
|
|
10
|
+
* tests partition it to verify range boundaries and shared claim capacity.
|
|
11
|
+
*/
|
|
11
12
|
export declare const ShardMap: Context.Reference<readonly BucketRange[]>;
|
|
13
|
+
/** Refuses ranges that overlap or leave the bucket space. */
|
|
14
|
+
export declare const checkRanges: (ranges: ReadonlyArray<BucketRange>) => boolean;
|
|
15
|
+
/** The runtime's scheduling ranges, checked before any scan runs. */
|
|
16
|
+
export declare const currentRanges: Effect.Effect<readonly BucketRange[], never, never>;
|
|
17
|
+
/** The ranges as scans read them, in bucket order. */
|
|
18
|
+
export declare const shardRanges: Effect.Effect<BucketRange[], never, never>;
|
|
19
|
+
/**
|
|
20
|
+
* Captures the runtime's scheduling ranges for calls from outside fibers,
|
|
21
|
+
* such as a holder transport's, so every scan uses the same range boundaries.
|
|
22
|
+
*/
|
|
23
|
+
export declare const locatedHere: Effect.Effect<<A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, never>>, never, never>;
|
|
24
|
+
/**
|
|
25
|
+
* Runs a scan once per scheduling range. `withinRange` keeps each statement
|
|
26
|
+
* within its inclusive buckets so no row is visited twice.
|
|
27
|
+
*/
|
|
28
|
+
export declare const forEachRange: <A, E, R>(effect: (range: BucketRange) => Effect.Effect<A, E, R>) => Effect.Effect<A[], E, R>;
|
|
12
29
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* Untargeted ranges reuse the existing client without a setting or a lease.
|
|
30
|
+
* `AND <column> BETWEEN` the routing keys of `range`'s buckets, or nothing for
|
|
31
|
+
* the whole key space, so an unsharded database runs the statement unchanged.
|
|
32
|
+
* `WHERE` starts the predicate for a statement that has none.
|
|
17
33
|
*/
|
|
18
|
-
export declare const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
34
|
+
export declare const withinRange: ({ sql, range, column, keyword, }: {
|
|
35
|
+
readonly sql: SqlClient.SqlClient;
|
|
36
|
+
readonly range: BucketRange;
|
|
37
|
+
readonly column: string;
|
|
38
|
+
readonly keyword?: "AND" | "WHERE";
|
|
39
|
+
}) => import("effect/sql/Statement").Fragment;
|
|
@@ -1,37 +1,49 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Context, Effect, Layer } from "effect";
|
|
3
|
-
import { SqlClient } from "effect/sql";
|
|
1
|
+
import { Context, Effect } from "effect";
|
|
4
2
|
import { BUCKETS } from "../turn/outbox.js";
|
|
5
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* Bucket ranges on one database. The default covers the whole key space;
|
|
5
|
+
* tests partition it to verify range boundaries and shared claim capacity.
|
|
6
|
+
*/
|
|
6
7
|
export const ShardMap = Context.Reference("akter/ShardMap", {
|
|
7
8
|
defaultValue: () => [BUCKETS],
|
|
8
9
|
});
|
|
9
|
-
/**
|
|
10
|
-
|
|
11
|
-
* scope. A shard setting cannot leak into the shared off-turn pool, and a
|
|
12
|
-
* failed setup closes the session instead of returning it to another user.
|
|
13
|
-
* Untargeted ranges reuse the existing client without a setting or a lease.
|
|
14
|
-
*/
|
|
15
|
-
export const shardClients = Effect.gen(function* () {
|
|
16
|
-
const sql = yield* SqlClient.SqlClient;
|
|
17
|
-
const ranges = yield* ShardMap;
|
|
10
|
+
/** Refuses ranges that overlap or leave the bucket space. */
|
|
11
|
+
export const checkRanges = (ranges) => {
|
|
18
12
|
const sorted = [...ranges].sort((a, b) => a.first - b.first);
|
|
19
|
-
for (const [index, range] of sorted.entries())
|
|
13
|
+
for (const [index, range] of sorted.entries())
|
|
20
14
|
if (!Number.isInteger(range.first) ||
|
|
21
15
|
!Number.isInteger(range.last) ||
|
|
22
16
|
range.first < BUCKETS.first ||
|
|
23
17
|
range.last > BUCKETS.last ||
|
|
24
18
|
range.first > range.last ||
|
|
25
|
-
(index > 0 && sorted[index - 1].last >= range.first)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return { range, sql: client };
|
|
36
|
-
}));
|
|
19
|
+
(index > 0 && sorted[index - 1].last >= range.first))
|
|
20
|
+
return false;
|
|
21
|
+
return true;
|
|
22
|
+
};
|
|
23
|
+
/** The runtime's scheduling ranges, checked before any scan runs. */
|
|
24
|
+
export const currentRanges = Effect.gen(function* () {
|
|
25
|
+
const ranges = yield* ShardMap;
|
|
26
|
+
if (!checkRanges(ranges))
|
|
27
|
+
return yield* Effect.die(new Error("Invalid or overlapping shard bucket ranges"));
|
|
28
|
+
return ranges;
|
|
37
29
|
});
|
|
30
|
+
/** The ranges as scans read them, in bucket order. */
|
|
31
|
+
export const shardRanges = Effect.map(currentRanges, (ranges) => [...ranges].sort((a, b) => a.first - b.first));
|
|
32
|
+
/**
|
|
33
|
+
* Captures the runtime's scheduling ranges for calls from outside fibers,
|
|
34
|
+
* such as a holder transport's, so every scan uses the same range boundaries.
|
|
35
|
+
*/
|
|
36
|
+
export const locatedHere = Effect.map(ShardMap, (map) => (effect) => Effect.provideService(effect, ShardMap, map));
|
|
37
|
+
/**
|
|
38
|
+
* Runs a scan once per scheduling range. `withinRange` keeps each statement
|
|
39
|
+
* within its inclusive buckets so no row is visited twice.
|
|
40
|
+
*/
|
|
41
|
+
export const forEachRange = (effect) => Effect.flatMap(shardRanges, (ranges) => Effect.forEach(ranges, effect));
|
|
42
|
+
/**
|
|
43
|
+
* `AND <column> BETWEEN` the routing keys of `range`'s buckets, or nothing for
|
|
44
|
+
* the whole key space, so an unsharded database runs the statement unchanged.
|
|
45
|
+
* `WHERE` starts the predicate for a statement that has none.
|
|
46
|
+
*/
|
|
47
|
+
export const withinRange = ({ sql, range, column, keyword = "AND", }) => range.first === BUCKETS.first && range.last === BUCKETS.last
|
|
48
|
+
? sql.literal("")
|
|
49
|
+
: sql `${sql.literal(keyword)} ${sql.literal(column)} BETWEEN ${BigInt(range.first) << 56n} AND ${(BigInt(range.last + 1) << 56n) - 1n}`;
|
|
@@ -9,6 +9,7 @@ import { ActorRef } from "../../identity/caller.ts";
|
|
|
9
9
|
import type { Authorize } from "../connections/streams.ts";
|
|
10
10
|
import type { Transport } from "../connections/transport.ts";
|
|
11
11
|
import { DefectLog } from "../telemetry/defects.ts";
|
|
12
|
+
import type { LiveRecorder } from "../telemetry/live.ts";
|
|
12
13
|
/**
|
|
13
14
|
* The commands an activation holds, waiting and in its current batch, when its
|
|
14
15
|
* policy declares no `mailboxCapacity`. Cluster refuses the next, which
|
|
@@ -297,7 +298,7 @@ export declare const registerActor: (registration: Registration, transport: Tran
|
|
|
297
298
|
readonly open: boolean;
|
|
298
299
|
close: Effect.Effect<void, never, never>;
|
|
299
300
|
expire: Effect.Effect<number, never, never>;
|
|
300
|
-
}, writable: Effect.Effect<void, ActorError, never
|
|
301
|
+
}, writable: Effect.Effect<void, ActorError, never>, recorder: () => LiveRecorder | undefined) => Effect.Effect<{
|
|
301
302
|
isResident: (entityId: string) => boolean;
|
|
302
303
|
owner: {
|
|
303
304
|
activations: Map<string, import("../connections/owner.ts").Activation>;
|
|
@@ -419,6 +420,12 @@ export declare const registerActor: (registration: Registration, transport: Tran
|
|
|
419
420
|
};
|
|
420
421
|
/** This type's view of one activation, for a delivery that timed out. */
|
|
421
422
|
diagnose: (entityId: string) => ActivationDiagnosis;
|
|
423
|
+
/** The activations of this type resident now, with the commands waiting in each mailbox. */
|
|
424
|
+
resident: () => {
|
|
425
|
+
tenant: string;
|
|
426
|
+
id: string;
|
|
427
|
+
mailbox: number;
|
|
428
|
+
}[];
|
|
422
429
|
/** Activations of this type being rebuilt or restarted in place now. */
|
|
423
430
|
restarting: () => string[];
|
|
424
431
|
}, never, Crypto.Crypto | DefectLog | Scope.Scope | Sharding.Sharding | SqlClient.SqlClient>;
|
|
@@ -5,7 +5,7 @@ import { SqlClient, SqlError } from "effect/sql";
|
|
|
5
5
|
import { ActorError, ActorUnavailable } from "../../errors/actor.js";
|
|
6
6
|
import { DeliveryFailed, Executed, Outcome, Request } from "../request.js";
|
|
7
7
|
import {} from "../members.js";
|
|
8
|
-
import { ActorRef } from "../../identity/caller.js";
|
|
8
|
+
import { ActorRef, callerKey } from "../../identity/caller.js";
|
|
9
9
|
import { bootstrapTicks } from "../cron/schedule.js";
|
|
10
10
|
import { parentPlacement, routingKey } from "../storage/codec.js";
|
|
11
11
|
import { ShardLease } from "../topology/locks.js";
|
|
@@ -158,7 +158,8 @@ const keepSingletonAwake = Effect.fnUntraced(function* (registration, entity, se
|
|
|
158
158
|
actor: registration.name,
|
|
159
159
|
id: "singleton",
|
|
160
160
|
});
|
|
161
|
-
|
|
161
|
+
const key = routingKey({ ref, placement: registration.placement });
|
|
162
|
+
yield* bootstrapTicks(key, ref, registration.cron).pipe(Effect.provideContext(services), Effect.orDie);
|
|
162
163
|
const address = yield* encodeEntityId([registration.tenant, "singleton"]).pipe(Effect.orDie);
|
|
163
164
|
const client = (yield* sharding.makeClient(entity))(address);
|
|
164
165
|
const wakeInterval = Duration.min(SINGLETON_WAKE_INTERVAL, Duration.millis(registration.policy.idleMs / 2));
|
|
@@ -207,7 +208,9 @@ const keepSingletonAwake = Effect.fnUntraced(function* (registration, entity, se
|
|
|
207
208
|
*/
|
|
208
209
|
export const registerActor = Effect.fnUntraced(function* (registration, transport, authorize, gate,
|
|
209
210
|
/** Fails while this runtime may not start turns, e.g. its payload writer rows are stale. */
|
|
210
|
-
writable
|
|
211
|
+
writable,
|
|
212
|
+
/** The live recorder, once the inspector enabled one. */
|
|
213
|
+
recorder) {
|
|
211
214
|
const sharding = yield* Sharding.Sharding;
|
|
212
215
|
const defects = yield* DefectLog;
|
|
213
216
|
const typeAttributes = { actor_type: registration.name };
|
|
@@ -221,7 +224,8 @@ writable) {
|
|
|
221
224
|
});
|
|
222
225
|
const ownedOf = (entityId) => Effect.flatMap(Effect.orDie(decodeEntityId(entityId)), ([tenant, id]) => {
|
|
223
226
|
const ref = { actor: registration.name, tenant, id };
|
|
224
|
-
|
|
227
|
+
const key = routingKey({ ref, placement: registration.placement });
|
|
228
|
+
return owner.enter(entityId, ref, key);
|
|
225
229
|
});
|
|
226
230
|
const services = yield* Effect.context();
|
|
227
231
|
const usage = Context.getUnsafe(services, UsageAccounting);
|
|
@@ -231,6 +235,7 @@ writable) {
|
|
|
231
235
|
const workflowRoutes = workflowCommands({ registration, routingKeyOf, services });
|
|
232
236
|
const waited = new Set([...registration.workflows.values()].flatMap((workflow) => [...workflow.member.registry.steps.values()].flatMap((step) => step.event === undefined ? [] : [step.event])));
|
|
233
237
|
const resident = new Map();
|
|
238
|
+
const residentRefs = new Map();
|
|
234
239
|
const building = new Set();
|
|
235
240
|
const workers = new Map();
|
|
236
241
|
const lease = registration.singleton
|
|
@@ -240,10 +245,15 @@ writable) {
|
|
|
240
245
|
* Counts a handler of `entityId` as resident until its scope closes; a
|
|
241
246
|
* rebuilt handler can overlap its predecessor, hence the count.
|
|
242
247
|
*/
|
|
243
|
-
const residentWhile = (entityId
|
|
248
|
+
const residentWhile = (entityId, tenant, id) => Effect.acquireRelease(Effect.sync(() => {
|
|
249
|
+
resident.set(entityId, (resident.get(entityId) ?? 0) + 1);
|
|
250
|
+
residentRefs.set(entityId, { tenant, id });
|
|
251
|
+
}).pipe(Effect.andThen(count(Metrics.activationsStarted, typeAttributes, 1)), Effect.andThen(Metric.modify(activations, 1))), () => Effect.sync(() => {
|
|
244
252
|
const left = resident.get(entityId) - 1;
|
|
245
|
-
if (left === 0)
|
|
253
|
+
if (left === 0) {
|
|
246
254
|
resident.delete(entityId);
|
|
255
|
+
residentRefs.delete(entityId);
|
|
256
|
+
}
|
|
247
257
|
else
|
|
248
258
|
resident.set(entityId, left);
|
|
249
259
|
}).pipe(Effect.andThen(Metric.modify(activations, -1))));
|
|
@@ -268,6 +278,38 @@ writable) {
|
|
|
268
278
|
yield* count(Metrics.outboxStaged, { kind: "intent" }, done.written.intents);
|
|
269
279
|
yield* count(Metrics.outboxStaged, { kind: "job" }, done.written.jobs);
|
|
270
280
|
});
|
|
281
|
+
/**
|
|
282
|
+
* Hands each command of a committed batch that wrote a receipt to the live
|
|
283
|
+
* recorder and the tenant's command streams. A replay, a refusal and an
|
|
284
|
+
* acknowledged delivery wrote none. The turn's time is its transaction's on
|
|
285
|
+
* the database clock, from the fenced read to the clock read after `COMMIT`.
|
|
286
|
+
*/
|
|
287
|
+
const recordLive = (live, batch, done, nowMs) => {
|
|
288
|
+
const durationMs = Math.max(0, done.endedAtMs - done.startedAtMs);
|
|
289
|
+
for (const [index, settled] of done.settled.entries()) {
|
|
290
|
+
if (Result.isFailure(settled) || done.replays.has(index))
|
|
291
|
+
continue;
|
|
292
|
+
const outcome = settled.success;
|
|
293
|
+
const failure = Outcome.guards.Failure(outcome) ? outcome.value : undefined;
|
|
294
|
+
if (!Outcome.guards.Success(outcome) && failure === undefined)
|
|
295
|
+
continue;
|
|
296
|
+
const { request } = batch[index];
|
|
297
|
+
const failed = failure !== undefined;
|
|
298
|
+
live.record(request.ref.tenant, registration.name, request.command, durationMs, nowMs);
|
|
299
|
+
live.publish(request.ref.tenant, nowMs, () => ({
|
|
300
|
+
commandId: request.commandId,
|
|
301
|
+
atMs: done.endedAtMs,
|
|
302
|
+
durationMs,
|
|
303
|
+
actorType: registration.name,
|
|
304
|
+
actorId: request.ref.id,
|
|
305
|
+
command: request.command,
|
|
306
|
+
callerKey: callerKey(request.caller),
|
|
307
|
+
failed,
|
|
308
|
+
payload: request.payload,
|
|
309
|
+
failure,
|
|
310
|
+
}));
|
|
311
|
+
}
|
|
312
|
+
};
|
|
271
313
|
/**
|
|
272
314
|
* Records a deterministic defect in the defect log under its turn span's
|
|
273
315
|
* name and trace, and marks the span's outcome.
|
|
@@ -333,7 +375,7 @@ writable) {
|
|
|
333
375
|
let refused;
|
|
334
376
|
const handler = yield* Scope.fork(activation);
|
|
335
377
|
memory.handler = handler;
|
|
336
|
-
yield* residentWhile(entityId).pipe(Scope.provide(handler));
|
|
378
|
+
yield* residentWhile(entityId, tenant, id).pipe(Scope.provide(handler));
|
|
337
379
|
const start = Effect.gen(function* () {
|
|
338
380
|
const scope = yield* Scope.fork(handler);
|
|
339
381
|
if (lease !== undefined)
|
|
@@ -437,6 +479,9 @@ writable) {
|
|
|
437
479
|
"turn.outcome": labels[0],
|
|
438
480
|
});
|
|
439
481
|
yield* countWritten(done);
|
|
482
|
+
const live = recorder();
|
|
483
|
+
if (live !== undefined && done.written.receipts > 0)
|
|
484
|
+
recordLive(live, batch, done, yield* Clock.currentTimeMillis);
|
|
440
485
|
if (owner.hasProgress) {
|
|
441
486
|
for (const [index, settled] of done.settled.entries())
|
|
442
487
|
if (Result.isSuccess(settled) && !Outcome.guards.Defect(settled.success))
|
|
@@ -658,6 +703,12 @@ writable) {
|
|
|
658
703
|
building: building.has(entityId),
|
|
659
704
|
...(workers.get(entityId)?.() ?? { worker: "none", mailbox: 0, batch: 0 }),
|
|
660
705
|
}),
|
|
706
|
+
/** The activations of this type resident now, with the commands waiting in each mailbox. */
|
|
707
|
+
resident: () => [...residentRefs].map(([entityId, { tenant, id }]) => ({
|
|
708
|
+
tenant,
|
|
709
|
+
id,
|
|
710
|
+
mailbox: workers.get(entityId)?.().mailbox ?? 0,
|
|
711
|
+
})),
|
|
661
712
|
/** Activations of this type being rebuilt or restarted in place now. */
|
|
662
713
|
restarting: () => [
|
|
663
714
|
...new Set([
|
|
@@ -54,9 +54,9 @@ export const checkFleet = Effect.fnUntraced(function* (views, tenantRole) {
|
|
|
54
54
|
if (table === undefined)
|
|
55
55
|
return yield* refuse(`${view.name} reads ${source}, which does not exist; apply its drizzle-kit migration`);
|
|
56
56
|
if (!table.published)
|
|
57
|
-
return yield* refuse(`${source} is not in publication ${FLEET_PUBLICATION}; run
|
|
57
|
+
return yield* refuse(`${source} is not in publication ${FLEET_PUBLICATION}; run akter fleet setup`);
|
|
58
58
|
if (table.identity !== "f")
|
|
59
|
-
return yield* refuse(`${source} does not have full replica identity; run
|
|
59
|
+
return yield* refuse(`${source} does not have full replica identity; run akter fleet setup (ALTER TABLE ${source} REPLICA IDENTITY FULL)`);
|
|
60
60
|
const leading = [view.routingColumn, view.tenantColumn, ...view.groupColumns];
|
|
61
61
|
const indexes = yield* sql `
|
|
62
62
|
SELECT array(
|
|
@@ -88,9 +88,9 @@ export const checkFleet = Effect.fnUntraced(function* (views, tenantRole) {
|
|
|
88
88
|
SELECT wal_status FROM pg_replication_slots
|
|
89
89
|
WHERE slot_name = ${FLEET_SLOT} AND database = current_database() AND slot_type = 'logical'`;
|
|
90
90
|
if (slot === undefined)
|
|
91
|
-
return yield* refuse(`replication slot ${FLEET_SLOT} does not exist; run
|
|
91
|
+
return yield* refuse(`replication slot ${FLEET_SLOT} does not exist; run akter fleet setup`);
|
|
92
92
|
if (slot.wal_status === "lost")
|
|
93
|
-
return yield* refuse(`replication slot ${FLEET_SLOT} is lost; run
|
|
93
|
+
return yield* refuse(`replication slot ${FLEET_SLOT} is lost; run akter fleet setup to recreate it, and every view rebuilds`);
|
|
94
94
|
const at = yield* Clock.currentTimeMillis;
|
|
95
95
|
for (const { view, sourceSchema } of resolved) {
|
|
96
96
|
yield* sql `INSERT INTO actor_fleet_views (view_name, source_schema, source_table, definition_hash,
|
|
@@ -31,7 +31,7 @@ export interface ResolvedView {
|
|
|
31
31
|
* the two replays a batch whose recompute is idempotent. When no change is
|
|
32
32
|
* waiting it rebuilds `building` and `stale` views a few tenants at a time.
|
|
33
33
|
* A view whose recompute fails is marked stale with its error and skipped
|
|
34
|
-
* until `
|
|
34
|
+
* until `akter fleet rebuild`, so it never stops the others. A slot that
|
|
35
35
|
* is missing, lost, or moved by anyone else marks every view stale. The
|
|
36
36
|
* runner that cannot take the lock retries every `LOCK_RETRY`.
|
|
37
37
|
*/
|
|
@@ -101,7 +101,7 @@ const innermost = (error) => {
|
|
|
101
101
|
* the two replays a batch whose recompute is idempotent. When no change is
|
|
102
102
|
* waiting it rebuilds `building` and `stale` views a few tenants at a time.
|
|
103
103
|
* A view whose recompute fails is marked stale with its error and skipped
|
|
104
|
-
* until `
|
|
104
|
+
* until `akter fleet rebuild`, so it never stops the others. A slot that
|
|
105
105
|
* is missing, lost, or moved by anyone else marks every view stale. The
|
|
106
106
|
* runner that cannot take the lock retries every `LOCK_RETRY`.
|
|
107
107
|
*/
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -21,6 +21,8 @@ export { ASSERTION_SKEW_MS, AssertionClaims, AssertionKey, AssertionKeySet, KeyR
|
|
|
21
21
|
export type { AssertionOptions } from "../serve/assertion/verify.ts";
|
|
22
22
|
export { actorErrorBody, closeCodeOf, statusOf } from "../protocol/wire.ts";
|
|
23
23
|
export { Database } from "./layer.ts";
|
|
24
|
+
export { App, AppLayerFailed } from "./app.ts";
|
|
25
|
+
export type { AppActor, AppServices } from "./app.ts";
|
|
24
26
|
export { Runner } from "./runner.ts";
|
|
25
27
|
export type { SocketRunnerOptions } from "./runner.ts";
|
|
26
28
|
export type { MutualTlsOptions } from "./peering/transport.ts";
|
package/dist/runtime/index.js
CHANGED
|
@@ -10,6 +10,7 @@ export const Auth = { none, make, jwt, assertion };
|
|
|
10
10
|
export { ASSERTION_SKEW_MS, AssertionClaims, AssertionKey, AssertionKeySet, KeyRefreshClaims, MAX_ASSERTION_SECONDS, } from "../serve/assertion/verify.js";
|
|
11
11
|
export { actorErrorBody, closeCodeOf, statusOf } from "../protocol/wire.js";
|
|
12
12
|
export { Database } from "./layer.js";
|
|
13
|
+
export { App, AppLayerFailed } from "./app.js";
|
|
13
14
|
export { Runner } from "./runner.js";
|
|
14
15
|
export { RunnerAuthority } from "./peering/authority.js";
|
|
15
16
|
export { DataDirLocked, DataDirVersion } from "../errors/database.js";
|
|
@@ -11,6 +11,10 @@ export interface InspectorOptions<R> {
|
|
|
11
11
|
readonly auth: AuthProvider<R>;
|
|
12
12
|
/** Prefix for every route. Default `"/inspector"`. */
|
|
13
13
|
readonly basePath?: `/${string}`;
|
|
14
|
+
/** The name live reads give this runner, such as its host or task; null in them when unset. */
|
|
15
|
+
readonly runner?: string | undefined;
|
|
16
|
+
/** The region live reads say this runner serves; null in them when unset. */
|
|
17
|
+
readonly region?: string | undefined;
|
|
14
18
|
}
|
|
15
19
|
/**
|
|
16
20
|
* Serves read-only JSON over the `durable` inspection views as routes on the
|
|
@@ -37,6 +41,22 @@ export interface InspectorOptions<R> {
|
|
|
37
41
|
* - `GET /outbox`, `/jobs`, `/dead-letters?afterDeadAtMs&afterJobId`,
|
|
38
42
|
* `/workflows?status=open|all|running|suspended|finished|completed|failed&afterStartedAtMs&afterExecutionId`:
|
|
39
43
|
* tenant-wide lists; the paged ones answer the `next` cursor to pass back.
|
|
44
|
+
*
|
|
45
|
+
* Inside a runtime it also serves the schedules and this runner's own memory,
|
|
46
|
+
* each live answer naming the runner, its region, when it began recording and
|
|
47
|
+
* how many other runners the cluster lists:
|
|
48
|
+
*
|
|
49
|
+
* - `GET /schedules`: each declared cron entry with its pending ticks and last committed tick.
|
|
50
|
+
* - `GET /live/overview`: recent rates, resident activations and the deepest mailbox, by type.
|
|
51
|
+
* - `GET /live/activity?type&window`, `/live/latency?type&window`: one type's, or every type's,
|
|
52
|
+
* committed turns over `1h`, `24h` (default) or `7d`.
|
|
53
|
+
* - `GET /live/actors?type&ids`: whether each named actor is resident, its
|
|
54
|
+
* mailbox, sockets and feeds; `ids` is a JSON array of at most 100.
|
|
55
|
+
* - `GET /live/connections`: open sockets and SSE responses, by type.
|
|
56
|
+
* - `GET /commands/stream?type&outcome&after`: SSE of each command this runner
|
|
57
|
+
* commits for the tenant, `id` its position, resuming after `after` while the
|
|
58
|
+
* runner still holds it and sending `gap` when it does not, until the
|
|
59
|
+
* credential expires.
|
|
40
60
|
*/
|
|
41
61
|
declare const serve: <R = never>(options: InspectorOptions<R>) => import("effect/Layer").Layer<never, never, HttpRouter.HttpRouter | SqlClient.SqlClient | Exclude<R, import("effect/Scope").Scope>>;
|
|
42
62
|
/** The read-only inspector: `serve` mounts its routes. */
|