@tenetkit/pg 0.42.0 → 0.43.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/README.md +34 -0
- package/dist/postgres/events/transaction-events.d.ts +3 -0
- package/dist/postgres/events/transaction-events.js +5 -4
- package/dist/postgres/index.d.ts +1 -1
- package/dist/postgres/index.js +1 -1
- package/dist/postgres/runtime-layer.d.ts +19 -3
- package/dist/postgres/runtime-layer.js +18 -5
- package/dist/postgres/store/claims.d.ts +2 -1
- package/dist/postgres/store/claims.js +54 -5
- package/dist/postgres/store/fan-out.d.ts +1 -3
- package/dist/postgres/store/fan-out.js +2 -4
- package/dist/postgres/store/index.d.ts +3 -3
- package/dist/postgres/store/index.js +3 -3
- package/dist/postgres/store/inspection.d.ts +1 -1
- package/dist/postgres/store/inspection.js +4 -4
- package/dist/postgres/store/runtime.js +2 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,3 +1,37 @@
|
|
|
1
1
|
# @tenetkit/pg
|
|
2
2
|
|
|
3
3
|
PostgreSQL runtime backend for TenetKit.
|
|
4
|
+
|
|
5
|
+
## Shared client
|
|
6
|
+
|
|
7
|
+
`layer(options)` uses a caller-supplied Effect `PgClient`. Provide the same client Layer to the host so host SQL and TenetKit Runtime operations share one transaction service:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { PgClient } from "@effect/sql-pg"
|
|
11
|
+
import { Effect, Layer, Redacted } from "effect"
|
|
12
|
+
import { SqlClient } from "effect/unstable/sql"
|
|
13
|
+
import { layer } from "@tenetkit/pg"
|
|
14
|
+
import { Run, Runtime } from "tenetkit/runtime"
|
|
15
|
+
|
|
16
|
+
declare const options: Parameters<typeof layer>[0]
|
|
17
|
+
declare const admission: Runtime.AdmitInput
|
|
18
|
+
|
|
19
|
+
const client = PgClient.layer({ url: Redacted.make("postgres://localhost/app") })
|
|
20
|
+
const app = layer(options).pipe(Layer.provideMerge(client))
|
|
21
|
+
|
|
22
|
+
const admitWithHostRow = Effect.gen(function* () {
|
|
23
|
+
const sql = yield* SqlClient.SqlClient
|
|
24
|
+
const runtime = yield* Runtime.Runtime
|
|
25
|
+
const receipt: Run.RunReceipt = yield* sql.withTransaction(
|
|
26
|
+
Effect.gen(function* () {
|
|
27
|
+
yield* sql`INSERT INTO host_jobs (id) VALUES (${admission.idempotencyKey})`
|
|
28
|
+
return yield* runtime.admit(admission)
|
|
29
|
+
}),
|
|
30
|
+
)
|
|
31
|
+
return receipt
|
|
32
|
+
}).pipe(Effect.provide(app))
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Runtime admission nests through the exact same Effect SQL transaction service, so nested use keeps Effect SQL savepoint behavior. PostgreSQL notifications run on that transaction connection and become visible only after the outermost commit; rollback removes both host and Runtime rows without emitting a notification.
|
|
36
|
+
|
|
37
|
+
`layerPostgres(options)` remains the convenient URL-backed constructor. Schema deployment stays separate through `RunSchema.plan`, `RunSchema.check`, and `RunSchema.apply`.
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { PgClient } from "@effect/sql-pg";
|
|
3
3
|
import { SqlClient } from "effect/unstable/sql";
|
|
4
|
+
import type { SqlError } from "effect/unstable/sql/SqlError";
|
|
4
5
|
import type { EventHub } from "tenetkit/runtime/driver/sql/subscribers";
|
|
5
6
|
import type { RunFn } from "../store/ops.js";
|
|
7
|
+
/** @experimental Notify event followers through the active SQL connection. */
|
|
8
|
+
export declare const notifyRun: (runId: string) => Effect.Effect<void, SqlError, SqlClient.SqlClient>;
|
|
6
9
|
export declare const transactionRunner: (input: {
|
|
7
10
|
readonly sql: SqlClient.SqlClient;
|
|
8
11
|
readonly pg: PgClient.PgClient;
|
|
@@ -4,6 +4,8 @@ import { SqlClient } from "effect/unstable/sql";
|
|
|
4
4
|
import { withSql } from "tenetkit/runtime/driver/sql/effect";
|
|
5
5
|
import { NOTIFY_CHANNEL } from "../schema.js";
|
|
6
6
|
const TransactionEvents = Context.Reference("tenetkit/runtime/driver/sql/postgres/TransactionEvents", { defaultValue: () => [] });
|
|
7
|
+
/** @experimental Notify event followers through the active SQL connection. */
|
|
8
|
+
export const notifyRun = (runId) => SqlClient.SqlClient.pipe(Effect.flatMap((sql) => sql `SELECT pg_notify(${NOTIFY_CHANNEL}, ${runId})`), Effect.asVoid);
|
|
7
9
|
export const transactionRunner = (input) => {
|
|
8
10
|
const transactionHub = {
|
|
9
11
|
...input.hub,
|
|
@@ -13,10 +15,9 @@ export const transactionRunner = (input) => {
|
|
|
13
15
|
const run = (effect) => runRaw(Effect.gen(function* () {
|
|
14
16
|
const events = [];
|
|
15
17
|
const result = yield* effect.pipe(Effect.provideService(TransactionEvents, events));
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
.pipe(Effect.catch((error) => Effect.logWarning("runtime.postgres.event_notification.failed").pipe(Effect.annotateLogs({ "tenetkit.run.id": runId, "tenetkit.failure": String(error) })))), { discard: true })), Effect.map(([result]) => result));
|
|
18
|
+
yield* Effect.forEach(new Set(events.map(([runId]) => runId)), notifyRun, { discard: true });
|
|
19
|
+
return result;
|
|
20
|
+
}));
|
|
20
21
|
const runNoTxn = (effect) => withSql(input.sql, effect.pipe(Effect.provideService(PgClient.PgClient, input.pg)));
|
|
21
22
|
return { run, runNoTxn, transactionHub };
|
|
22
23
|
};
|
package/dist/postgres/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { layerPostgres, type
|
|
1
|
+
export { layer, layerPostgres, type PostgresOptions, type PostgresUrlOptions, type PostgresStoreError, } from "./runtime-layer.js";
|
|
2
2
|
export * as RunSchema from "./run-schema.js";
|
|
3
3
|
export * from "tenetkit/runtime";
|
package/dist/postgres/index.js
CHANGED
|
@@ -1,14 +1,30 @@
|
|
|
1
1
|
import { Layer } from "effect";
|
|
2
|
+
import { PgClient } from "@effect/sql-pg";
|
|
2
3
|
import type { SqlError } from "effect/unstable/sql/SqlError";
|
|
3
4
|
import { Runtime, type LayerOptions } from "tenetkit/runtime/driver/service";
|
|
4
5
|
import { RunStore } from "tenetkit/runtime/driver/run/store";
|
|
5
6
|
import { RunClaims } from "tenetkit/runtime/driver/sql/run/claims";
|
|
6
7
|
import { ExecutionHost } from "tenetkit/runtime/driver/execution/host";
|
|
7
8
|
import { SchemaMigrationFailed, type SchemaChecksumMismatch, type SchemaDirty, type SchemaUpgradeRequired, type SchemaVersionUnsupported } from "tenetkit/runtime/driver/sql/errors";
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
/** @experimental PostgreSQL Runtime options independent of client acquisition. */
|
|
10
|
+
export interface PostgresOptions extends LayerOptions {
|
|
10
11
|
readonly source?: string;
|
|
12
|
+
}
|
|
13
|
+
/** @experimental PostgreSQL Runtime options for the URL-backed convenience Layer. */
|
|
14
|
+
export interface PostgresUrlOptions extends PostgresOptions {
|
|
15
|
+
readonly url: string;
|
|
11
16
|
readonly maxConnections?: number;
|
|
12
17
|
}
|
|
18
|
+
/** @experimental PostgreSQL Runtime construction failures. */
|
|
13
19
|
export type PostgresStoreError = SchemaDirty | SchemaChecksumMismatch | SchemaVersionUnsupported | SchemaUpgradeRequired | SchemaMigrationFailed;
|
|
14
|
-
|
|
20
|
+
type PostgresServices = Runtime | RunStore | RunClaims | ExecutionHost;
|
|
21
|
+
/**
|
|
22
|
+
* @experimental Build the PostgreSQL Runtime from the caller's `PgClient`.
|
|
23
|
+
*
|
|
24
|
+
* Host transactions must use the `SqlClient` exposed by the same client Layer. Runtime operations
|
|
25
|
+
* then nest through that exact transaction service and therefore use PostgreSQL savepoints.
|
|
26
|
+
*/
|
|
27
|
+
export declare const layer: (options: PostgresOptions) => Layer.Layer<PostgresServices, PostgresStoreError | SqlError, PgClient.PgClient>;
|
|
28
|
+
/** @experimental Build the PostgreSQL Runtime and its client from a URL. */
|
|
29
|
+
export declare const layerPostgres: (options: PostgresUrlOptions) => Layer.Layer<PostgresServices, PostgresStoreError | SqlError>;
|
|
30
|
+
export {};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Context, Effect, Layer } from "effect";
|
|
2
|
+
import { PgClient } from "@effect/sql-pg";
|
|
3
|
+
import { SqlClient } from "effect/unstable/sql";
|
|
2
4
|
import { makeRuntime } from "tenetkit/runtime/driver/memory/layer";
|
|
3
5
|
import { Runtime } from "tenetkit/runtime/driver/service";
|
|
4
6
|
import { RunStore } from "tenetkit/runtime/driver/run/store";
|
|
@@ -9,6 +11,21 @@ import { layer as activeExecutionsLayer } from "tenetkit/runtime/driver/executio
|
|
|
9
11
|
import { layer as modelPreviewLayer } from "tenetkit/runtime/driver/execution/model-response/preview";
|
|
10
12
|
import { SchemaMigrationFailed, } from "tenetkit/runtime/driver/sql/errors";
|
|
11
13
|
import { layerClient } from "./client.js";
|
|
14
|
+
/**
|
|
15
|
+
* @experimental Build the PostgreSQL Runtime from the caller's `PgClient`.
|
|
16
|
+
*
|
|
17
|
+
* Host transactions must use the `SqlClient` exposed by the same client Layer. Runtime operations
|
|
18
|
+
* then nest through that exact transaction service and therefore use PostgreSQL savepoints.
|
|
19
|
+
*/
|
|
20
|
+
export const layer = (options) => {
|
|
21
|
+
const client = Layer.effectContext(PgClient.PgClient.pipe(Effect.map((pg) => Context.make(PgClient.PgClient, pg).pipe(Context.add(SqlClient.SqlClient, pg)))));
|
|
22
|
+
const services = Layer.effectContext(postgresServices(options).pipe(Effect.map(({ store, claims }) => Context.make(RunStore, store).pipe(Context.add(RunClaims, claims))))).pipe(Layer.provide(client));
|
|
23
|
+
const dependencies = Layer.mergeAll(services, activeExecutionsLayer, modelPreviewLayer);
|
|
24
|
+
const runtime = Layer.effect(Runtime, makeRuntime(options)).pipe(Layer.provide(dependencies));
|
|
25
|
+
const host = Layer.effect(ExecutionHost, makeExecutionHost({ workerId: "postgres", resolver: options.resolver })).pipe(Layer.provide(dependencies));
|
|
26
|
+
return Layer.mergeAll(runtime, host, services);
|
|
27
|
+
};
|
|
28
|
+
/** @experimental Build the PostgreSQL Runtime and its client from a URL. */
|
|
12
29
|
export const layerPostgres = (options) => {
|
|
13
30
|
const maxConnections = options.maxConnections ?? 10;
|
|
14
31
|
const client = Layer.unwrap(Effect.gen(function* () {
|
|
@@ -20,9 +37,5 @@ export const layerPostgres = (options) => {
|
|
|
20
37
|
}
|
|
21
38
|
return layerClient({ url: options.url, maxConnections });
|
|
22
39
|
}));
|
|
23
|
-
|
|
24
|
-
const dependencies = Layer.mergeAll(services, activeExecutionsLayer, modelPreviewLayer);
|
|
25
|
-
const runtime = Layer.effect(Runtime, makeRuntime(options)).pipe(Layer.provide(dependencies));
|
|
26
|
-
const host = Layer.effect(ExecutionHost, makeExecutionHost({ workerId: "postgres", resolver: options.resolver })).pipe(Layer.provide(dependencies));
|
|
27
|
-
return Layer.mergeAll(runtime, host, services);
|
|
40
|
+
return layer(options).pipe(Layer.provide(client));
|
|
28
41
|
};
|
|
@@ -9,7 +9,8 @@ import type { WithoutSqlError } from "tenetkit/runtime/driver/sql/effect";
|
|
|
9
9
|
type SqlR = SqlClient.SqlClient | PgClient.PgClient;
|
|
10
10
|
export type RunFn = <A, E>(effect: Effect.Effect<A, E | SqlError, SqlR>) => Effect.Effect<A, WithoutSqlError<E | SqlError> | RuntimeUnavailable>;
|
|
11
11
|
export declare const postgresClaims: (input: {
|
|
12
|
-
readonly
|
|
12
|
+
readonly pg: PgClient.PgClient;
|
|
13
|
+
readonly source: string;
|
|
13
14
|
readonly hub: EventHub;
|
|
14
15
|
readonly run: RunFn;
|
|
15
16
|
readonly cancelRun: (runId: string, reason: string | undefined) => Effect.Effect<void, RunNotFound | RunTerminal | RuntimeUnavailable | SqlError, SqlR>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { Effect, Schema } from "effect";
|
|
1
|
+
import { Cause, Duration, Effect, Queue, Redacted, Schema, Stream } from "effect";
|
|
2
2
|
import { SqlClient } from "effect/unstable/sql";
|
|
3
|
+
import { Client, escapeIdentifier } from "pg";
|
|
3
4
|
import { AgentExecutionFailure, RunNotFound, RunTerminal, RuntimeUnavailable, failureMessage, } from "tenetkit/runtime/driver/errors";
|
|
4
5
|
import { isTerminal } from "tenetkit/runtime/driver/run";
|
|
5
6
|
import { StaleClaim } from "tenetkit/runtime/driver/sql/errors";
|
|
@@ -8,9 +9,54 @@ import { RunClaims } from "tenetkit/runtime/driver/sql/run/claims";
|
|
|
8
9
|
import { afterTerminal, appendEvent, completeRun, loadEventsAfter, loadRun, settleParent } from "./runtime.js";
|
|
9
10
|
import { lockRunHierarchy } from "../runs/locks.js";
|
|
10
11
|
import { ExecutionResult } from "tenetkit/runtime/driver/execution/state";
|
|
12
|
+
import { NOTIFY_CHANNEL } from "../schema.js";
|
|
13
|
+
import { notifyRun } from "../events/transaction-events.js";
|
|
14
|
+
const wakeupChanges = (config, source) => Stream.callback((queue) => {
|
|
15
|
+
const client = new Client({
|
|
16
|
+
connectionString: config.url === undefined ? undefined : Redacted.value(config.url),
|
|
17
|
+
user: config.username,
|
|
18
|
+
host: config.host,
|
|
19
|
+
database: config.database,
|
|
20
|
+
password: config.password === undefined ? undefined : Redacted.value(config.password),
|
|
21
|
+
ssl: config.ssl,
|
|
22
|
+
port: config.port,
|
|
23
|
+
...(config.stream === undefined ? undefined : { stream: config.stream }),
|
|
24
|
+
connectionTimeoutMillis: config.connectTimeout === undefined ? undefined : Duration.toMillis(config.connectTimeout),
|
|
25
|
+
application_name: `tenetkit-runtime-worker:${source}`.slice(0, 63),
|
|
26
|
+
types: config.types,
|
|
27
|
+
});
|
|
28
|
+
const failure = (cause) => RuntimeUnavailable.make({ message: `PostgreSQL RunClaims wakeup listener failed: ${String(cause)}` });
|
|
29
|
+
const onNotification = (notification) => {
|
|
30
|
+
if (notification.channel === NOTIFY_CHANNEL)
|
|
31
|
+
Queue.offerUnsafe(queue, undefined);
|
|
32
|
+
};
|
|
33
|
+
const onFailure = (cause) => Queue.failCauseUnsafe(queue, Cause.fail(failure(cause)));
|
|
34
|
+
const onEnd = () => onFailure("PostgreSQL listener connection ended");
|
|
35
|
+
const close = Effect.tryPromise(() => client.end()).pipe(Effect.ignore);
|
|
36
|
+
const acquire = Effect.acquireRelease(Effect.sync(() => {
|
|
37
|
+
client.on("notification", onNotification);
|
|
38
|
+
client.on("error", onFailure);
|
|
39
|
+
client.on("end", onEnd);
|
|
40
|
+
}), () => Effect.sync(() => {
|
|
41
|
+
client.off("notification", onNotification);
|
|
42
|
+
client.off("error", onFailure);
|
|
43
|
+
client.off("end", onEnd);
|
|
44
|
+
}).pipe(Effect.andThen(close)));
|
|
45
|
+
const connect = Effect.tryPromise({
|
|
46
|
+
try: () => client.connect(),
|
|
47
|
+
catch: failure,
|
|
48
|
+
}).pipe(Effect.andThen(Effect.tryPromise({
|
|
49
|
+
try: () => client.query(`LISTEN ${escapeIdentifier(NOTIFY_CHANNEL)}`),
|
|
50
|
+
catch: failure,
|
|
51
|
+
})), Effect.andThen(Effect.sync(() => {
|
|
52
|
+
Queue.offerUnsafe(queue, undefined);
|
|
53
|
+
})));
|
|
54
|
+
return acquire.pipe(Effect.andThen(connect));
|
|
55
|
+
}, { bufferSize: 1, strategy: "sliding" });
|
|
11
56
|
export const postgresClaims = (input) => {
|
|
12
57
|
const { hub, run, cancelRun } = input;
|
|
13
58
|
return RunClaims.of({
|
|
59
|
+
changes: wakeupChanges(input.pg.config, input.source),
|
|
14
60
|
claimReadyRuns: (claimInput) => run(Effect.gen(function* () {
|
|
15
61
|
const claimed = yield* claimReadyRuns({
|
|
16
62
|
workerId: claimInput.workerId,
|
|
@@ -34,10 +80,13 @@ export const postgresClaims = (input) => {
|
|
|
34
80
|
cancellationRequested: leaseInput.cancellationRequested,
|
|
35
81
|
lease: leaseInput.lease ?? "30 seconds",
|
|
36
82
|
})),
|
|
37
|
-
releaseClaim: (releaseInput) => run(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
83
|
+
releaseClaim: (releaseInput) => run(Effect.gen(function* () {
|
|
84
|
+
yield* releaseClaim({
|
|
85
|
+
runId: releaseInput.runId,
|
|
86
|
+
workerId: releaseInput.workerId,
|
|
87
|
+
attemptFence: releaseInput.attemptFence,
|
|
88
|
+
});
|
|
89
|
+
yield* notifyRun(releaseInput.runId);
|
|
41
90
|
})),
|
|
42
91
|
commitWithClaim: (commitInput) => run(Effect.gen(function* () {
|
|
43
92
|
yield* lockRunHierarchy(commitInput.runId);
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
|
-
import type { PgClient } from "@effect/sql-pg";
|
|
3
2
|
import type { SqlClient } from "effect/unstable/sql";
|
|
4
3
|
import type { Interface as RunStoreInterface } from "tenetkit/runtime/driver/run/store";
|
|
5
4
|
import type { EventHub } from "tenetkit/runtime/driver/sql/subscribers";
|
|
6
5
|
import type { WithoutSqlError } from "tenetkit/runtime/driver/sql/effect";
|
|
7
6
|
import type { SqlError } from "effect/unstable/sql/SqlError";
|
|
8
|
-
type SqlR = SqlClient.SqlClient
|
|
7
|
+
type SqlR = SqlClient.SqlClient;
|
|
9
8
|
export type Run = <A, E>(effect: Effect.Effect<A, E | SqlError, SqlR>) => Effect.Effect<A, WithoutSqlError<E | SqlError> | import("tenetkit/runtime/driver/errors").RuntimeUnavailable>;
|
|
10
9
|
export declare const fanOutStoreMethods: (input: {
|
|
11
10
|
readonly sql: SqlClient.SqlClient;
|
|
12
|
-
readonly pg: PgClient.PgClient;
|
|
13
11
|
readonly hub: EventHub;
|
|
14
12
|
readonly run: Run;
|
|
15
13
|
readonly runNoTxn: Run;
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { Effect, Function } from "effect";
|
|
2
2
|
import { admitFanOut, inspectFanOut } from "tenetkit/runtime/driver/sql/store/fan-out/service";
|
|
3
|
-
import {
|
|
3
|
+
import { notifyRun } from "../events/transaction-events.js";
|
|
4
4
|
export const fanOutStoreMethods = (input) => ({
|
|
5
|
-
admitFanOut: (fanOut) => input
|
|
6
|
-
.run(input.sql `SELECT run_id FROM tenetkit_runs WHERE run_id = ${fanOut.parentRunId} FOR UPDATE`.pipe(Effect.andThen(input.sql `SELECT pg_advisory_xact_lock(hashtext(${`fanout:${fanOut.parentRunId}:${fanOut.idempotencyKey}`}))`), Effect.andThen(admitFanOut(input.hub, fanOut))))
|
|
7
|
-
.pipe(Effect.tap((receipt) => input.runNoTxn(Effect.forEach([receipt.parentRunId, ...receipt.childRunIds], (runId) => input.pg.notify(NOTIFY_CHANNEL, runId), { discard: true })))),
|
|
5
|
+
admitFanOut: (fanOut) => input.run(input.sql `SELECT run_id FROM tenetkit_runs WHERE run_id = ${fanOut.parentRunId} FOR UPDATE`.pipe(Effect.andThen(input.sql `SELECT pg_advisory_xact_lock(hashtext(${`fanout:${fanOut.parentRunId}:${fanOut.idempotencyKey}`}))`), Effect.andThen(admitFanOut(input.hub, fanOut)), Effect.tap((receipt) => Effect.forEach([receipt.parentRunId, ...receipt.childRunIds], notifyRun, { discard: true })))),
|
|
8
6
|
inspectFanOut: (fanOutId) => input.runNoTxn(inspectFanOut(fanOutId)),
|
|
9
7
|
});
|
|
10
8
|
export const cancelOwnedFanOuts = Function.dual(2, (sql, parentRunId) => Effect.gen(function* () {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { SqlClient } from "effect/unstable/sql";
|
|
3
3
|
import "../schema.js";
|
|
4
|
-
import "tenetkit/runtime/driver/sql/tree-
|
|
4
|
+
import "tenetkit/runtime/driver/sql/tree-replay";
|
|
5
5
|
import "tenetkit/runtime/driver/sql/inspection/service";
|
|
6
|
-
import type {
|
|
7
|
-
export declare const postgresServices: (options:
|
|
6
|
+
import type { PostgresOptions } from "../runtime-layer.js";
|
|
7
|
+
export declare const postgresServices: (options: PostgresOptions) => Effect.Effect<{
|
|
8
8
|
store: import("tenetkit/runtime/driver/run/store").Interface;
|
|
9
9
|
claims: import("tenetkit/runtime/driver/sql/run/claims").Interface;
|
|
10
10
|
}, import("tenetkit/runtime/driver/sql/errors").SchemaChecksumMismatch | import("tenetkit/runtime/driver/sql/errors").SchemaDirty | import("tenetkit/runtime/driver/sql/errors").SchemaMigrationFailed | import("tenetkit/runtime/driver/sql/errors").SchemaUpgradeRequired | import("tenetkit/runtime/driver/sql/errors").SchemaVersionUnsupported | import("effect/unstable/sql/SqlError").SqlError, import("effect/Scope").Scope | SqlClient.SqlClient>;
|
|
@@ -24,7 +24,7 @@ import { hasAdmission, loadRunWait } from "tenetkit/runtime/driver/sql/store/sta
|
|
|
24
24
|
import { WaitResolution } from "tenetkit/runtime/driver/run/wait";
|
|
25
25
|
import { fanOutStoreMethods } from "./fan-out.js";
|
|
26
26
|
import { deferCancelledFanOutParent, cancelRunFor } from "./cancel.js";
|
|
27
|
-
import "tenetkit/runtime/driver/sql/tree-
|
|
27
|
+
import "tenetkit/runtime/driver/sql/tree-replay";
|
|
28
28
|
import "tenetkit/runtime/driver/sql/inspection/service";
|
|
29
29
|
import { withConsistentSnapshot } from "tenetkit/runtime/driver/sql/inspection/transaction";
|
|
30
30
|
import { StringArray, decodePinnedEffect, decodeStoredPinnedEffect, encodeJson, } from "tenetkit/runtime/driver/sql/codec/codecs";
|
|
@@ -370,10 +370,10 @@ export const postgresServices = (options) => Effect.gen(function* () {
|
|
|
370
370
|
releaseExecution: (input) => run(releaseExecution(input)),
|
|
371
371
|
saveExecution: (input) => run(saveExecution(input)),
|
|
372
372
|
retryExecution: (input) => run(lockRun(input.runId).pipe(Effect.andThen(retryExecution(transactionHub, input)))),
|
|
373
|
-
...fanOutStoreMethods({ sql,
|
|
373
|
+
...fanOutStoreMethods({ sql, hub: transactionHub, run, runNoTxn }),
|
|
374
374
|
...operations,
|
|
375
375
|
...programStoreMethods({ sql, hub: transactionHub, run, runNoTxn, lockRunHierarchy }),
|
|
376
376
|
});
|
|
377
|
-
const claims = postgresClaims({
|
|
377
|
+
const claims = postgresClaims({ pg, source, hub: transactionHub, run, cancelRun });
|
|
378
378
|
return { store, claims };
|
|
379
379
|
});
|
|
@@ -9,4 +9,4 @@ export declare const inspectionStoreMethods: (deps: {
|
|
|
9
9
|
readonly run: Run;
|
|
10
10
|
readonly runNoTxn: Run;
|
|
11
11
|
readonly runInspection: RunFn;
|
|
12
|
-
}) => Pick<RunStoreInterface, "inspect" | "snapshot" | "sessionRoots" | "
|
|
12
|
+
}) => Pick<RunStoreInterface, "inspect" | "snapshot" | "sessionRoots" | "treeCheckpoint" | "history" | "treeReplay" | "treeChanges">;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Effect, Stream } from "effect";
|
|
2
2
|
import { CursorExpired } from "tenetkit/runtime/driver/errors";
|
|
3
|
-
import { loadRunSnapshot,
|
|
3
|
+
import { loadRunSnapshot, loadTreeCheckpoint } from "tenetkit/runtime/driver/sql/inspection/service";
|
|
4
4
|
import { sessionRoots } from "tenetkit/runtime/driver/sql/session/lifecycle";
|
|
5
5
|
import { loadChildReadiness } from "tenetkit/runtime/driver/sql/store/child/capacity";
|
|
6
6
|
import { loadRunWait } from "tenetkit/runtime/driver/sql/store/statements";
|
|
7
|
-
import {
|
|
7
|
+
import { loadTreeReplay } from "tenetkit/runtime/driver/sql/tree-replay";
|
|
8
8
|
import { loadEventsAfter, loadRun, requireRun } from "./runtime.js";
|
|
9
9
|
import { NOTIFY_CHANNEL } from "../schema.js";
|
|
10
10
|
export const inspectionStoreMethods = (deps) => ({
|
|
@@ -28,7 +28,7 @@ export const inspectionStoreMethods = (deps) => ({
|
|
|
28
28
|
})),
|
|
29
29
|
snapshot: (runId) => deps.runInspection(loadRunSnapshot(runId)),
|
|
30
30
|
sessionRoots: (sessionId) => deps.runNoTxn(sessionRoots(sessionId)),
|
|
31
|
-
|
|
31
|
+
treeCheckpoint: (rootRunId) => deps.runInspection(loadTreeCheckpoint(rootRunId)),
|
|
32
32
|
history: (input) => deps.runNoTxn(Effect.gen(function* () {
|
|
33
33
|
const loaded = yield* requireRun(input.runId);
|
|
34
34
|
if (input.cursor < -1 || input.cursor > loaded.lastSequence) {
|
|
@@ -36,7 +36,7 @@ export const inspectionStoreMethods = (deps) => ({
|
|
|
36
36
|
}
|
|
37
37
|
return (yield* loadEventsAfter(input.runId, input.cursor)).slice(0, input.limit);
|
|
38
38
|
})),
|
|
39
|
-
|
|
39
|
+
treeReplay: (input) => deps.runNoTxn(loadTreeReplay(input)),
|
|
40
40
|
treeChanges: (rootRunId) => deps.hub.subscribeTree({
|
|
41
41
|
rootRunId,
|
|
42
42
|
onSubscribed: deps.pg.listen(NOTIFY_CHANNEL).pipe(Stream.runForEach((runId) => deps.runNoTxn(loadRun(runId)).pipe(Effect.flatMap((loaded) => (loaded?.rootRunId === rootRunId ? deps.hub.wakeTree(rootRunId) : Effect.void)), Effect.ignore)), Effect.ignore),
|
|
@@ -6,10 +6,10 @@ import { isTerminal } from "tenetkit/runtime/driver/run";
|
|
|
6
6
|
import { StringArray, decodeMessage, decodeEvent, decodeQueue, encodeExecutableManifest, encodeExecutableRef, encodeEvent, encodeJson, encodeMessage, encodeQueue, } from "tenetkit/runtime/driver/sql/codec/codecs";
|
|
7
7
|
import { reconcileFanOutWith } from "tenetkit/runtime/driver/sql/store/fan-out/service";
|
|
8
8
|
import { decodePersistedEvents, decodeRunEffect, nowIso } from "tenetkit/runtime/driver/sql/store/statements";
|
|
9
|
-
import { NOTIFY_CHANNEL } from "../schema.js";
|
|
10
9
|
import { PendingRunOutcome } from "tenetkit/runtime/driver/run/store";
|
|
11
10
|
import { RunNotFound, RunTerminal, RuntimeUnavailable } from "tenetkit/runtime/driver/errors";
|
|
12
11
|
import { StaleClaim } from "tenetkit/runtime/driver/sql/errors";
|
|
12
|
+
import { notifyRun } from "../events/transaction-events.js";
|
|
13
13
|
import { admitChildSettlementFromEventId } from "tenetkit/runtime/driver/sql/settlement-notifications";
|
|
14
14
|
import { discardPendingSteering } from "tenetkit/runtime/driver/sql/store/steering/disposition";
|
|
15
15
|
import { hasPendingOperationCancellation, hasUnsettledChild, loadTerminalEvent, reconcileChildWaitWith, } from "tenetkit/runtime/driver/sql/store/child/settlement";
|
|
@@ -83,7 +83,6 @@ export const allocateSequence = (runId) => Effect.gen(function* () {
|
|
|
83
83
|
});
|
|
84
84
|
export const appendEvent = Function.dual((args) => args.length >= 4 || (args.length === 3 && !("runId" in args[0])), (_hub, run, partial, nextStatus) => Effect.gen(function* () {
|
|
85
85
|
const sql = yield* SqlClient.SqlClient;
|
|
86
|
-
const pg = yield* PgClient.PgClient;
|
|
87
86
|
const discarded = yield* discardPendingSteering({ runId: run.runId, terminalTag: partial._tag });
|
|
88
87
|
if (discarded !== undefined) {
|
|
89
88
|
yield* appendEvent(_hub, run, discarded);
|
|
@@ -148,7 +147,7 @@ export const appendEvent = Function.dual((args) => args.length >= 4 || (args.len
|
|
|
148
147
|
WHERE run_id = ${run.runId}
|
|
149
148
|
`;
|
|
150
149
|
}
|
|
151
|
-
yield*
|
|
150
|
+
yield* notifyRun(run.runId);
|
|
152
151
|
return event;
|
|
153
152
|
}));
|
|
154
153
|
export const promoteHead = Function.dual(3, (hub, address, sessionId) => Effect.gen(function* () {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.43.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@effect/sql-pg": "4.0.0-rc.111",
|
|
42
42
|
"pg": "8.23.0",
|
|
43
|
-
"tenetkit": "0.
|
|
43
|
+
"tenetkit": "0.43.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@effect/vitest": "4.0.0-rc.111",
|