@alchemy.run/effect-cluster 0.0.0-stage → 2.0.0-beta.86
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/LICENSE +201 -0
- package/README.md +105 -2
- package/lib/AWS/Database.d.ts +54 -0
- package/lib/AWS/Database.d.ts.map +1 -0
- package/lib/AWS/Database.js +96 -0
- package/lib/AWS/Database.js.map +1 -0
- package/lib/AWS/EcsPool.d.ts +56 -0
- package/lib/AWS/EcsPool.d.ts.map +1 -0
- package/lib/AWS/EcsPool.js +87 -0
- package/lib/AWS/EcsPool.js.map +1 -0
- package/lib/AWS/index.d.ts +7 -0
- package/lib/AWS/index.d.ts.map +1 -0
- package/lib/AWS/index.js +7 -0
- package/lib/AWS/index.js.map +1 -0
- package/lib/AWS/internal/Gateway.d.ts +23 -0
- package/lib/AWS/internal/Gateway.d.ts.map +1 -0
- package/lib/AWS/internal/Gateway.js +70 -0
- package/lib/AWS/internal/Gateway.js.map +1 -0
- package/lib/Cloudflare/DurableObjectPool.d.ts +42 -0
- package/lib/Cloudflare/DurableObjectPool.d.ts.map +1 -0
- package/lib/Cloudflare/DurableObjectPool.js +136 -0
- package/lib/Cloudflare/DurableObjectPool.js.map +1 -0
- package/lib/Cloudflare/PoolWorker.d.ts +186 -0
- package/lib/Cloudflare/PoolWorker.d.ts.map +1 -0
- package/lib/Cloudflare/PoolWorker.js +75 -0
- package/lib/Cloudflare/PoolWorker.js.map +1 -0
- package/lib/Cloudflare/index.d.ts +7 -0
- package/lib/Cloudflare/index.d.ts.map +1 -0
- package/lib/Cloudflare/index.js +7 -0
- package/lib/Cloudflare/index.js.map +1 -0
- package/lib/Cloudflare/internal/Objects.d.ts +38 -0
- package/lib/Cloudflare/internal/Objects.d.ts.map +1 -0
- package/lib/Cloudflare/internal/Objects.js +102 -0
- package/lib/Cloudflare/internal/Objects.js.map +1 -0
- package/lib/Cron.d.ts +143 -0
- package/lib/Cron.d.ts.map +1 -0
- package/lib/Cron.js +83 -0
- package/lib/Cron.js.map +1 -0
- package/lib/Database.d.ts +95 -0
- package/lib/Database.d.ts.map +1 -0
- package/lib/Database.js +38 -0
- package/lib/Database.js.map +1 -0
- package/lib/Docker/Database.d.ts +42 -0
- package/lib/Docker/Database.d.ts.map +1 -0
- package/lib/Docker/Database.js +53 -0
- package/lib/Docker/Database.js.map +1 -0
- package/lib/Docker/SwarmPool.d.ts +44 -0
- package/lib/Docker/SwarmPool.d.ts.map +1 -0
- package/lib/Docker/SwarmPool.js +56 -0
- package/lib/Docker/SwarmPool.js.map +1 -0
- package/lib/Docker/index.d.ts +7 -0
- package/lib/Docker/index.d.ts.map +1 -0
- package/lib/Docker/index.js +7 -0
- package/lib/Docker/index.js.map +1 -0
- package/lib/Entity.d.ts +348 -0
- package/lib/Entity.d.ts.map +1 -0
- package/lib/Entity.js +308 -0
- package/lib/Entity.js.map +1 -0
- package/lib/Fly/Database.d.ts +50 -0
- package/lib/Fly/Database.d.ts.map +1 -0
- package/lib/Fly/Database.js +56 -0
- package/lib/Fly/Database.js.map +1 -0
- package/lib/Fly/MachinePool.d.ts +39 -0
- package/lib/Fly/MachinePool.d.ts.map +1 -0
- package/lib/Fly/MachinePool.js +51 -0
- package/lib/Fly/MachinePool.js.map +1 -0
- package/lib/Fly/index.d.ts +7 -0
- package/lib/Fly/index.d.ts.map +1 -0
- package/lib/Fly/index.js +7 -0
- package/lib/Fly/index.js.map +1 -0
- package/lib/GCP/ComputeEnginePool.d.ts +41 -0
- package/lib/GCP/ComputeEnginePool.d.ts.map +1 -0
- package/lib/GCP/ComputeEnginePool.js +172 -0
- package/lib/GCP/ComputeEnginePool.js.map +1 -0
- package/lib/GCP/Database.d.ts +48 -0
- package/lib/GCP/Database.d.ts.map +1 -0
- package/lib/GCP/Database.js +115 -0
- package/lib/GCP/Database.js.map +1 -0
- package/lib/GCP/index.d.ts +7 -0
- package/lib/GCP/index.d.ts.map +1 -0
- package/lib/GCP/index.js +7 -0
- package/lib/GCP/index.js.map +1 -0
- package/lib/Hetzner/Database.d.ts +48 -0
- package/lib/Hetzner/Database.d.ts.map +1 -0
- package/lib/Hetzner/Database.js +91 -0
- package/lib/Hetzner/Database.js.map +1 -0
- package/lib/Hetzner/ServerPool.d.ts +35 -0
- package/lib/Hetzner/ServerPool.d.ts.map +1 -0
- package/lib/Hetzner/ServerPool.js +98 -0
- package/lib/Hetzner/ServerPool.js.map +1 -0
- package/lib/Hetzner/index.d.ts +7 -0
- package/lib/Hetzner/index.d.ts.map +1 -0
- package/lib/Hetzner/index.js +7 -0
- package/lib/Hetzner/index.js.map +1 -0
- package/lib/Host.d.ts +60 -0
- package/lib/Host.d.ts.map +1 -0
- package/lib/Host.js +31 -0
- package/lib/Host.js.map +1 -0
- package/lib/Kubernetes/Database.d.ts +40 -0
- package/lib/Kubernetes/Database.d.ts.map +1 -0
- package/lib/Kubernetes/Database.js +56 -0
- package/lib/Kubernetes/Database.js.map +1 -0
- package/lib/Kubernetes/DeploymentPool.d.ts +54 -0
- package/lib/Kubernetes/DeploymentPool.d.ts.map +1 -0
- package/lib/Kubernetes/DeploymentPool.js +49 -0
- package/lib/Kubernetes/DeploymentPool.js.map +1 -0
- package/lib/Kubernetes/index.d.ts +7 -0
- package/lib/Kubernetes/index.d.ts.map +1 -0
- package/lib/Kubernetes/index.js +7 -0
- package/lib/Kubernetes/index.js.map +1 -0
- package/lib/Pool.d.ts +66 -0
- package/lib/Pool.d.ts.map +1 -0
- package/lib/Pool.js +47 -0
- package/lib/Pool.js.map +1 -0
- package/lib/Providers.d.ts +19 -0
- package/lib/Providers.d.ts.map +1 -0
- package/lib/Providers.js +31 -0
- package/lib/Providers.js.map +1 -0
- package/lib/ShardGroups.d.ts +24 -0
- package/lib/ShardGroups.d.ts.map +1 -0
- package/lib/ShardGroups.js +19 -0
- package/lib/ShardGroups.js.map +1 -0
- package/lib/Singleton.d.ts +110 -0
- package/lib/Singleton.d.ts.map +1 -0
- package/lib/Singleton.js +60 -0
- package/lib/Singleton.js.map +1 -0
- package/lib/Workflow.d.ts +251 -0
- package/lib/Workflow.d.ts.map +1 -0
- package/lib/Workflow.js +288 -0
- package/lib/Workflow.js.map +1 -0
- package/lib/index.d.ts +12 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +12 -0
- package/lib/index.js.map +1 -0
- package/lib/internal/Bootstrap.d.ts +28 -0
- package/lib/internal/Bootstrap.d.ts.map +1 -0
- package/lib/internal/Bootstrap.js +257 -0
- package/lib/internal/Bootstrap.js.map +1 -0
- package/lib/internal/EntityRuntime.d.ts +40 -0
- package/lib/internal/EntityRuntime.d.ts.map +1 -0
- package/lib/internal/EntityRuntime.js +698 -0
- package/lib/internal/EntityRuntime.js.map +1 -0
- package/lib/internal/Gateway.d.ts +82 -0
- package/lib/internal/Gateway.d.ts.map +1 -0
- package/lib/internal/Gateway.js +218 -0
- package/lib/internal/Gateway.js.map +1 -0
- package/lib/internal/HostedPlatform.d.ts +36 -0
- package/lib/internal/HostedPlatform.d.ts.map +1 -0
- package/lib/internal/HostedPlatform.js +36 -0
- package/lib/internal/HostedPlatform.js.map +1 -0
- package/lib/internal/HostedRuntime.d.ts +58 -0
- package/lib/internal/HostedRuntime.d.ts.map +1 -0
- package/lib/internal/HostedRuntime.js +72 -0
- package/lib/internal/HostedRuntime.js.map +1 -0
- package/lib/internal/Naming.d.ts +12 -0
- package/lib/internal/Naming.d.ts.map +1 -0
- package/lib/internal/Naming.js +40 -0
- package/lib/internal/Naming.js.map +1 -0
- package/lib/internal/ObjectSharding.d.ts +141 -0
- package/lib/internal/ObjectSharding.d.ts.map +1 -0
- package/lib/internal/ObjectSharding.js +337 -0
- package/lib/internal/ObjectSharding.js.map +1 -0
- package/lib/internal/PoolHost.d.ts +80 -0
- package/lib/internal/PoolHost.d.ts.map +1 -0
- package/lib/internal/PoolHost.js +203 -0
- package/lib/internal/PoolHost.js.map +1 -0
- package/lib/internal/PoolHostService.d.ts +25 -0
- package/lib/internal/PoolHostService.d.ts.map +1 -0
- package/lib/internal/PoolHostService.js +10 -0
- package/lib/internal/PoolHostService.js.map +1 -0
- package/lib/internal/Wire.d.ts +60 -0
- package/lib/internal/Wire.d.ts.map +1 -0
- package/lib/internal/Wire.js +36 -0
- package/lib/internal/Wire.js.map +1 -0
- package/lib/internal/WorkflowGateway.d.ts +36 -0
- package/lib/internal/WorkflowGateway.d.ts.map +1 -0
- package/lib/internal/WorkflowGateway.js +124 -0
- package/lib/internal/WorkflowGateway.js.map +1 -0
- package/lib/internal/external-runner.d.ts +2 -0
- package/lib/internal/external-runner.d.ts.map +1 -0
- package/lib/internal/external-runner.js +7 -0
- package/lib/internal/external-runner.js.map +1 -0
- package/lib/internal/runner.d.ts +2 -0
- package/lib/internal/runner.d.ts.map +1 -0
- package/lib/internal/runner.js +5 -0
- package/lib/internal/runner.js.map +1 -0
- package/package.json +143 -3
- package/src/AWS/Database.ts +139 -0
- package/src/AWS/EcsPool.ts +118 -0
- package/src/AWS/index.ts +6 -0
- package/src/AWS/internal/Gateway.ts +82 -0
- package/src/Cloudflare/DurableObjectPool.ts +198 -0
- package/src/Cloudflare/PoolWorker.ts +124 -0
- package/src/Cloudflare/index.ts +6 -0
- package/src/Cloudflare/internal/Objects.ts +160 -0
- package/src/Cron.ts +202 -0
- package/src/Database.ts +116 -0
- package/src/Docker/Database.ts +94 -0
- package/src/Docker/SwarmPool.ts +83 -0
- package/src/Docker/index.ts +6 -0
- package/src/Entity.ts +621 -0
- package/src/Fly/Database.ts +102 -0
- package/src/Fly/MachinePool.ts +72 -0
- package/src/Fly/index.ts +6 -0
- package/src/GCP/ComputeEnginePool.ts +203 -0
- package/src/GCP/Database.ts +168 -0
- package/src/GCP/index.ts +6 -0
- package/src/Hetzner/Database.ts +142 -0
- package/src/Hetzner/ServerPool.ts +116 -0
- package/src/Hetzner/index.ts +6 -0
- package/src/Host.ts +68 -0
- package/src/Kubernetes/Database.ts +89 -0
- package/src/Kubernetes/DeploymentPool.ts +77 -0
- package/src/Kubernetes/index.ts +6 -0
- package/src/Pool.ts +104 -0
- package/src/Providers.ts +49 -0
- package/src/ShardGroups.ts +41 -0
- package/src/Singleton.ts +153 -0
- package/src/Workflow.ts +556 -0
- package/src/index.ts +11 -0
- package/src/internal/Bootstrap.ts +368 -0
- package/src/internal/EntityRuntime.ts +996 -0
- package/src/internal/Gateway.ts +366 -0
- package/src/internal/HostedPlatform.ts +83 -0
- package/src/internal/HostedRuntime.ts +118 -0
- package/src/internal/Naming.ts +44 -0
- package/src/internal/ObjectSharding.ts +578 -0
- package/src/internal/PoolHost.ts +330 -0
- package/src/internal/PoolHostService.ts +25 -0
- package/src/internal/Wire.ts +83 -0
- package/src/internal/WorkflowGateway.ts +188 -0
- package/src/internal/external-runner.ts +10 -0
- package/src/internal/runner.ts +5 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { Input } from "alchemy/Input";
|
|
2
|
+
import * as Output from "alchemy/Output";
|
|
3
|
+
import { Stack } from "alchemy/Stack";
|
|
4
|
+
import * as Effect from "effect/Effect";
|
|
5
|
+
import * as Layer from "effect/Layer";
|
|
6
|
+
import { Database, type DatabaseShape } from "../Database.ts";
|
|
7
|
+
import { Pool } from "../Pool.ts";
|
|
8
|
+
import type { Providers } from "../Providers.ts";
|
|
9
|
+
import { PoolHost } from "./PoolHostService.ts";
|
|
10
|
+
declare const DatabaseNetworkMismatch_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
11
|
+
readonly _tag: "Cluster.DatabaseNetworkMismatch";
|
|
12
|
+
} & Readonly<A>;
|
|
13
|
+
/** The pool was given a database whose network it cannot join. */
|
|
14
|
+
export declare class DatabaseNetworkMismatch extends DatabaseNetworkMismatch_base<{
|
|
15
|
+
readonly message: string;
|
|
16
|
+
}> {
|
|
17
|
+
}
|
|
18
|
+
export interface PoolSettings {
|
|
19
|
+
/**
|
|
20
|
+
* The name the pool is known by. It is also the shard group the
|
|
21
|
+
* entities they host are placed in.
|
|
22
|
+
* @default ${stack}-${stage}-${id}
|
|
23
|
+
*/
|
|
24
|
+
name?: string;
|
|
25
|
+
/**
|
|
26
|
+
* The shard groups an external program's entities use, which these
|
|
27
|
+
* runners serve. Entities declared with Alchemy always use the pool's
|
|
28
|
+
* own group.
|
|
29
|
+
* @default ["default"]
|
|
30
|
+
*/
|
|
31
|
+
shardGroups?: string[];
|
|
32
|
+
}
|
|
33
|
+
/** What a host needs to declare the service that runs the pool. */
|
|
34
|
+
export interface PoolNodes<Network, Gateway extends PoolGateway = PoolGateway> {
|
|
35
|
+
/** What the host declared for the gateway (e.g. a load balancer to register with). */
|
|
36
|
+
readonly gateway: Gateway;
|
|
37
|
+
readonly database: DatabaseShape;
|
|
38
|
+
readonly network: Network;
|
|
39
|
+
readonly pool: Pool;
|
|
40
|
+
/** The pool's name, a DNS label. */
|
|
41
|
+
readonly name: string;
|
|
42
|
+
/**
|
|
43
|
+
* The bundled program: a directory holding `runner.mjs` with a
|
|
44
|
+
* `Dockerfile`, and a hash of its
|
|
45
|
+
* contents, which changes whenever the program does.
|
|
46
|
+
*/
|
|
47
|
+
readonly program: Output.Output<{
|
|
48
|
+
readonly dir: string;
|
|
49
|
+
readonly hash: string;
|
|
50
|
+
}>;
|
|
51
|
+
/** Environment every runner needs, as plain strings. */
|
|
52
|
+
readonly environment: Output.Output<Record<string, string>>;
|
|
53
|
+
}
|
|
54
|
+
/** What a host binds onto each entity so callers can reach the gateway. */
|
|
55
|
+
export interface PoolGateway {
|
|
56
|
+
readonly url: Input<string>;
|
|
57
|
+
}
|
|
58
|
+
/** The Dockerfile every host builds the runner image from. */
|
|
59
|
+
export declare const RUNNER_DOCKERFILE = "FROM node:26-slim\nWORKDIR /app\nCOPY *.mjs /app/\nENV NODE_ENV=production\nEXPOSE 34431 34500\nENTRYPOINT [\"node\", \"/app/runner.mjs\"]\n";
|
|
60
|
+
/**
|
|
61
|
+
* A pool Layer: `network` narrows the database's network to the one this
|
|
62
|
+
* host can join; `gateway` names where callers reach the pool;
|
|
63
|
+
* `nodes` declares the service that runs them.
|
|
64
|
+
*/
|
|
65
|
+
export declare const makePoolLayer: <Network, Req, Gateway extends PoolGateway = PoolGateway>(options: {
|
|
66
|
+
readonly label: string;
|
|
67
|
+
readonly id: string;
|
|
68
|
+
readonly settings: PoolSettings;
|
|
69
|
+
readonly network: (database: DatabaseShape) => Network | undefined;
|
|
70
|
+
readonly expected: string;
|
|
71
|
+
/** The longest runner name the host accepts. @default 63 */
|
|
72
|
+
readonly nameLength?: number;
|
|
73
|
+
/** The runner image's Dockerfile, when the host needs more than {@link RUNNER_DOCKERFILE}. */
|
|
74
|
+
readonly dockerfile?: string;
|
|
75
|
+
/** Where callers reach the gateway, declaring what it needs; before the pool's service. */
|
|
76
|
+
readonly gateway: (name: string, network: Network) => Effect.Effect<Gateway, never, Req>;
|
|
77
|
+
readonly nodes: (nodes: PoolNodes<Network, Gateway>) => Effect.Effect<void, never, Req>;
|
|
78
|
+
}) => Layer.Layer<PoolHost, never, Database | Stack | Providers | Req>;
|
|
79
|
+
export {};
|
|
80
|
+
//# sourceMappingURL=PoolHost.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PoolHost.d.ts","sources":["../../src/internal/PoolHost.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What every pool Layer shares, whatever runs its pool: register the
|
|
3
|
+
* entity whose Construction phase is running with the pool resource, bind
|
|
4
|
+
* what callers need onto the entity, and bundle every class the pool hosts
|
|
5
|
+
* into one Node program. A host only declares the service that runs it.
|
|
6
|
+
*
|
|
7
|
+
* @internal
|
|
8
|
+
*/
|
|
9
|
+
import { createHash } from "node:crypto";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
11
|
+
import { dotAlchemyDirectory } from "alchemy/AlchemyContext";
|
|
12
|
+
import * as Bundle from "alchemy/Bundle/Bundle";
|
|
13
|
+
import * as Output from "alchemy/Output";
|
|
14
|
+
import { Random } from "alchemy/Random";
|
|
15
|
+
import { Self } from "alchemy/Self";
|
|
16
|
+
import { Stack } from "alchemy/Stack";
|
|
17
|
+
import * as Data from "effect/Data";
|
|
18
|
+
import * as Effect from "effect/Effect";
|
|
19
|
+
import * as FileSystem from "effect/FileSystem";
|
|
20
|
+
import * as Layer from "effect/Layer";
|
|
21
|
+
import * as Option from "effect/Option";
|
|
22
|
+
import * as Path from "effect/Path";
|
|
23
|
+
import * as Redacted from "effect/Redacted";
|
|
24
|
+
import { Database } from "../Database.js";
|
|
25
|
+
import { shardGroupKey } from "../Entity.js";
|
|
26
|
+
import { Pool } from "../Pool.js";
|
|
27
|
+
import { GATEWAY_PORT, RUNNER_PORT } from "./Gateway.js";
|
|
28
|
+
import { HOSTED_TYPES, shortLabel, stackDnsLabel } from "./Naming.js";
|
|
29
|
+
import { PoolHost } from "./PoolHostService.js";
|
|
30
|
+
const VIRTUAL = "virtual:cluster-entities";
|
|
31
|
+
/** Resolve {@link VIRTUAL} to a module that imports every class the pool hosts. */
|
|
32
|
+
const entitiesPlugin = (entities) => {
|
|
33
|
+
const source = [
|
|
34
|
+
...entities.map((entity, i) => `import { ${entity.handler} as e${i} } from ${JSON.stringify(entity.module.startsWith("file:") ? fileURLToPath(entity.module) : entity.module)};`),
|
|
35
|
+
`export default [${entities
|
|
36
|
+
.map((entity, i) => `{ name: ${JSON.stringify(entity.name)}, value: e${i} }`)
|
|
37
|
+
.join(", ")}];`,
|
|
38
|
+
].join("\n");
|
|
39
|
+
return [
|
|
40
|
+
{
|
|
41
|
+
name: "cluster-entities",
|
|
42
|
+
resolveId: (id) => (id === VIRTUAL ? `\0${VIRTUAL}` : null),
|
|
43
|
+
load: (id) => (id === `\0${VIRTUAL}` ? source : null),
|
|
44
|
+
},
|
|
45
|
+
];
|
|
46
|
+
};
|
|
47
|
+
/** The pool was given a database whose network it cannot join. */
|
|
48
|
+
export class DatabaseNetworkMismatch extends Data.TaggedError("Cluster.DatabaseNetworkMismatch") {
|
|
49
|
+
}
|
|
50
|
+
const output = (value) => (Output.isOutput(value) ? value : Output.literal(value));
|
|
51
|
+
/** The Dockerfile every host builds the runner image from. */
|
|
52
|
+
export const RUNNER_DOCKERFILE = `FROM node:26-slim
|
|
53
|
+
WORKDIR /app
|
|
54
|
+
COPY *.mjs /app/
|
|
55
|
+
ENV NODE_ENV=production
|
|
56
|
+
EXPOSE ${RUNNER_PORT} ${GATEWAY_PORT}
|
|
57
|
+
ENTRYPOINT ["node", "/app/runner.mjs"]
|
|
58
|
+
`;
|
|
59
|
+
/**
|
|
60
|
+
* A pool Layer: `network` narrows the database's network to the one this
|
|
61
|
+
* host can join; `gateway` names where callers reach the pool;
|
|
62
|
+
* `nodes` declares the service that runs them.
|
|
63
|
+
*/
|
|
64
|
+
export const makePoolLayer = (options) => Layer.effect(PoolHost, Effect.gen(function* () {
|
|
65
|
+
const database = yield* Database;
|
|
66
|
+
// What was provided to the pool, like an entity's RPC middleware,
|
|
67
|
+
// goes with every class they host.
|
|
68
|
+
const services = yield* Effect.context();
|
|
69
|
+
const self = Option.getOrUndefined(yield* Effect.serviceOption(Self));
|
|
70
|
+
const hostsSelf = self !== undefined && HOSTED_TYPES.has(self.Type);
|
|
71
|
+
if (globalThis.__ALCHEMY_RUNTIME__) {
|
|
72
|
+
if (hostsSelf)
|
|
73
|
+
yield* self.provideServices(services);
|
|
74
|
+
return {
|
|
75
|
+
host: (hosted) => hosted.provideServices(services),
|
|
76
|
+
deployExternal: () => Effect.void,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
const network = options.network(database);
|
|
80
|
+
if (network === undefined) {
|
|
81
|
+
return yield* Effect.die(new DatabaseNetworkMismatch({
|
|
82
|
+
message: `${options.label} runs runners on ${options.expected}, and its database is not on one.`,
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
// Named up front, so an entity knows its pool without depending on
|
|
86
|
+
// the pool resource, whose bindings carry every entity's env.
|
|
87
|
+
const name = options.settings.name ?? (yield* stackDnsLabel(options.id, options.nameLength));
|
|
88
|
+
// A shard group only has to be unique within its database, and must
|
|
89
|
+
// never be one an external program uses (usually `default`). Effect
|
|
90
|
+
// Cluster stores `group:shard` in a 50-character column, so keep it short.
|
|
91
|
+
const group = `alchemy:${yield* shortLabel(options.id, 32)}`;
|
|
92
|
+
const gateway = yield* options.gateway(name, network);
|
|
93
|
+
const context = yield* Effect.context();
|
|
94
|
+
/** Put `hosted` on the pool, bind the gateway onto `resource`, and declare the pool. */
|
|
95
|
+
const deploy = (hosted, env, resource) => Effect.gen(function* () {
|
|
96
|
+
const pool = yield* Pool(options.id, { name });
|
|
97
|
+
const token = yield* Random(`${options.id}GatewayToken`, {
|
|
98
|
+
bytes: 32,
|
|
99
|
+
});
|
|
100
|
+
// The hosting runners route the entity to its own shard group.
|
|
101
|
+
yield* pool.bind `${hosted.name}`({
|
|
102
|
+
entities: [hosted],
|
|
103
|
+
env: hosted.program === undefined ? { ...env, [shardGroupKey(hosted.name)]: group } : env,
|
|
104
|
+
});
|
|
105
|
+
// Alchemy entities live in the pool's own shard group; an
|
|
106
|
+
// external program keeps the groups its entities use.
|
|
107
|
+
const groups = hosted.program === undefined ? [group] : (options.settings.shardGroups ?? ["default"]);
|
|
108
|
+
yield* database.shardGroups.bind `${name}`({ groups });
|
|
109
|
+
// What callers need to reach the entity through the gateway.
|
|
110
|
+
yield* resource.bind `Pool`({
|
|
111
|
+
pool: group,
|
|
112
|
+
gateway: gateway.url,
|
|
113
|
+
token: token.text,
|
|
114
|
+
});
|
|
115
|
+
const stack = yield* Stack;
|
|
116
|
+
yield* options.nodes({
|
|
117
|
+
gateway,
|
|
118
|
+
database,
|
|
119
|
+
network,
|
|
120
|
+
pool,
|
|
121
|
+
name,
|
|
122
|
+
program: yield* bundleProgram(options.id, pool, options.dockerfile ?? RUNNER_DOCKERFILE),
|
|
123
|
+
environment: Output.all(pool.env, output(database.url), token.text, database.shardGroups.groups).pipe(Output.map(([values, url, tokenText, allGroups]) => ({
|
|
124
|
+
...Object.fromEntries(Object.entries(values).map(([key, value]) => [key, String(value)])),
|
|
125
|
+
ALCHEMY_STACK_NAME: stack.name,
|
|
126
|
+
ALCHEMY_STAGE: stack.stage,
|
|
127
|
+
ALCHEMY_PHASE: "runtime",
|
|
128
|
+
CLUSTER_DATABASE_URL: Redacted.value(url),
|
|
129
|
+
CLUSTER_GATEWAY_TOKEN: Redacted.value(tokenText),
|
|
130
|
+
CLUSTER_POOL: name,
|
|
131
|
+
CLUSTER_SHARD_GROUPS: groups.join(","),
|
|
132
|
+
CLUSTER_AVAILABLE_SHARD_GROUPS: allGroups.join(","),
|
|
133
|
+
}))),
|
|
134
|
+
});
|
|
135
|
+
}).pipe(Effect.provide(context));
|
|
136
|
+
const host = (hosted) => Effect.andThen(hosted.provideServices(services), hosted.registerPool((env) => deploy({
|
|
137
|
+
name: hosted.LogicalId,
|
|
138
|
+
module: hosted.Props.main,
|
|
139
|
+
handler: hosted.Props.handler ?? "default",
|
|
140
|
+
}, env, hosted)));
|
|
141
|
+
// The generic `Self` is the class whose phase is running. When it is
|
|
142
|
+
// not hosted on runners, the pool was given an external entity,
|
|
143
|
+
// which may be declared inside any runtime's Construction phase.
|
|
144
|
+
if (hostsSelf)
|
|
145
|
+
yield* host(self);
|
|
146
|
+
return {
|
|
147
|
+
host,
|
|
148
|
+
deployExternal: ({ type, main, handler, program, resource }) =>
|
|
149
|
+
// oxlint-disable-next-line effecttsgo/unsafe-effect-type-assertion -- `bind` is typed `any`; what it needs is the providers in `context`
|
|
150
|
+
deploy({ name: type, module: main, handler, program }, {}, resource),
|
|
151
|
+
};
|
|
152
|
+
}));
|
|
153
|
+
const PROGRAM = "virtual:cluster-program";
|
|
154
|
+
/** Resolve {@link PROGRAM} to the external program's bundled source, as a string. */
|
|
155
|
+
const programPlugin = (source) => [
|
|
156
|
+
{
|
|
157
|
+
name: "cluster-program",
|
|
158
|
+
resolveId: (id) => (id === PROGRAM ? `\0${PROGRAM}` : null),
|
|
159
|
+
load: (id) => id === `\0${PROGRAM}` ? `export default ${JSON.stringify(source ?? "")};` : null,
|
|
160
|
+
},
|
|
161
|
+
];
|
|
162
|
+
/** A runner entry beside this module: `runner` (Alchemy entities) or `external-runner`. */
|
|
163
|
+
const runnerEntry = (name) => fileURLToPath(new URL(import.meta.url.endsWith(".ts") ? `./${name}.ts` : `./${name}.js`, import.meta.url));
|
|
164
|
+
/**
|
|
165
|
+
* Bundle the runner program and its Dockerfile into a directory of their
|
|
166
|
+
* own, once the pool knows its classes, and resolve to the directory.
|
|
167
|
+
*/
|
|
168
|
+
const bundleProgram = Effect.fn(function* (id, pool, dockerfile) {
|
|
169
|
+
const fs = yield* FileSystem.FileSystem;
|
|
170
|
+
const path = yield* Path.Path;
|
|
171
|
+
const dir = path.resolve(yield* dotAlchemyDirectory, "cluster", yield* stackDnsLabel(id));
|
|
172
|
+
return Output.mapEffect((entities) => Effect.gen(function* () {
|
|
173
|
+
yield* fs.remove(dir, { recursive: true, force: true });
|
|
174
|
+
yield* fs.makeDirectory(dir, { recursive: true });
|
|
175
|
+
// An external program is bundled on its own and embedded in the
|
|
176
|
+
// runner, which writes it out and runs it as its own process: it reads
|
|
177
|
+
// its settings from its environment when it loads, so it can't share
|
|
178
|
+
// the runner's modules. One file, on every host.
|
|
179
|
+
const program = entities.find((entity) => entity.program !== undefined)?.program;
|
|
180
|
+
let programSource;
|
|
181
|
+
if (program !== undefined) {
|
|
182
|
+
const programDir = path.join(dir, "program");
|
|
183
|
+
yield* Bundle.build({
|
|
184
|
+
input: path.resolve(program),
|
|
185
|
+
platform: "node",
|
|
186
|
+
resolve: { conditionNames: [...Bundle.NODE_CONDITION_NAMES] },
|
|
187
|
+
}, { dir: programDir, format: "esm", entryFileNames: "program.mjs", codeSplitting: false });
|
|
188
|
+
programSource = yield* fs.readFileString(path.join(programDir, "program.mjs"));
|
|
189
|
+
yield* fs.remove(programDir, { recursive: true });
|
|
190
|
+
}
|
|
191
|
+
const runner = yield* Bundle.build({
|
|
192
|
+
input: runnerEntry(program === undefined ? "runner" : "external-runner"),
|
|
193
|
+
platform: "node",
|
|
194
|
+
resolve: { conditionNames: [...Bundle.NODE_CONDITION_NAMES] },
|
|
195
|
+
plugins: [...entitiesPlugin(entities), ...programPlugin(programSource)],
|
|
196
|
+
}, { dir, format: "esm", entryFileNames: "runner.mjs", codeSplitting: false });
|
|
197
|
+
const hashes = [runner.hash, dockerfile];
|
|
198
|
+
yield* fs.writeFileString(path.join(dir, "Dockerfile"), dockerfile);
|
|
199
|
+
const hash = yield* Effect.sync(() => createHash("sha256").update(hashes.join("\n")).digest("hex").slice(0, 16));
|
|
200
|
+
return { dir, hash };
|
|
201
|
+
}).pipe(Effect.orDie))(pool.entities);
|
|
202
|
+
});
|
|
203
|
+
//# sourceMappingURL=PoolHost.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PoolHost.js","sources":["../../src/internal/PoolHost.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as Context from "effect/Context";
|
|
2
|
+
import type * as Effect from "effect/Effect";
|
|
3
|
+
import type { Entity } from "../Entity.ts";
|
|
4
|
+
import type { HostedClass } from "./HostedRuntime.ts";
|
|
5
|
+
declare const PoolHost_base: Context.ServiceClass<PoolHost, "Cluster.PoolHost", {
|
|
6
|
+
/** Host a class (an entity, a workflow) on the pool: its Construction phase is running. */
|
|
7
|
+
readonly host: (self: HostedClass) => Effect.Effect<void>;
|
|
8
|
+
readonly deployExternal: (entity: {
|
|
9
|
+
readonly type: string;
|
|
10
|
+
readonly main: string;
|
|
11
|
+
readonly handler: string;
|
|
12
|
+
readonly program: string;
|
|
13
|
+
readonly resource: Entity;
|
|
14
|
+
}) => Effect.Effect<void>;
|
|
15
|
+
}>;
|
|
16
|
+
/**
|
|
17
|
+
* What a pool Layer gives the Effect it is provided to: a way for an
|
|
18
|
+
* external `Cluster.Entity` (an existing Effect Cluster program, referenced
|
|
19
|
+
* by file) to run on the pool.
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
export declare class PoolHost extends PoolHost_base {
|
|
23
|
+
}
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=PoolHostService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PoolHostService.d.ts","sources":["../../src/internal/PoolHostService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,KAAK,MAAM,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;;IAWlD,2FAA2F;mBAC5E,CAAC,IAAI,EAAE,WAAW,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;6BAChC,CAAC,MAAM,EAAE;QAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;KAC3B,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;;AAjB7B;;;;;GAKG;AACH,qBAAa,QAAS,SAAQ,aAaP;CAAG"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as Context from "effect/Context";
|
|
2
|
+
/**
|
|
3
|
+
* What a pool Layer gives the Effect it is provided to: a way for an
|
|
4
|
+
* external `Cluster.Entity` (an existing Effect Cluster program, referenced
|
|
5
|
+
* by file) to run on the pool.
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export class PoolHost extends Context.Service()("Cluster.PoolHost") {
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=PoolHostService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PoolHostService.js","sources":["../../src/internal/PoolHostService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAK1C;;;;;GAKG;AACH,MAAM,OAAO,QAAS,SAAQ,OAAO,CAAC,OAAO,EAa1C,CAAC,kBAAkB,CAAC;CAAG"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What crosses between a caller and an entity's object: each call as JSON,
|
|
3
|
+
* its reply as JSON. A host's object RPC hides a thrown error's type, so
|
|
4
|
+
* failures of the object itself come back as data too.
|
|
5
|
+
*
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
import * as Effect from "effect/Effect";
|
|
9
|
+
import * as Exit from "effect/Exit";
|
|
10
|
+
import { Rpc } from "effect/rpc";
|
|
11
|
+
import * as Schema from "effect/Schema";
|
|
12
|
+
/** One call to an entity, as it crosses to the entity's object. */
|
|
13
|
+
export interface Call {
|
|
14
|
+
/** The caller's id for this call: what an interrupt names. */
|
|
15
|
+
readonly requestId: string;
|
|
16
|
+
readonly tag: string;
|
|
17
|
+
readonly payload: unknown;
|
|
18
|
+
readonly headers: Record<string, string>;
|
|
19
|
+
}
|
|
20
|
+
/** A failure of the object itself, returned as data. */
|
|
21
|
+
export declare const DEFECT = "~cluster/defect";
|
|
22
|
+
/** A cluster error the object answered with instead of running the call. */
|
|
23
|
+
export interface Rejection {
|
|
24
|
+
readonly _tag: "MailboxFull" | "AlreadyProcessingMessage" | "PersistenceError";
|
|
25
|
+
readonly message: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The object's answer to a call: the encoded exit of an RPC, a rejection,
|
|
29
|
+
* or the object's own defect. A stream answers with one of these per frame,
|
|
30
|
+
* plus `{ chunk }` frames before its exit.
|
|
31
|
+
*/
|
|
32
|
+
export type Reply = {
|
|
33
|
+
readonly exit: unknown;
|
|
34
|
+
} | {
|
|
35
|
+
readonly rejected: Rejection;
|
|
36
|
+
} | {
|
|
37
|
+
readonly [DEFECT]: string;
|
|
38
|
+
};
|
|
39
|
+
export type Frame = Reply | {
|
|
40
|
+
readonly chunk: ReadonlyArray<unknown>;
|
|
41
|
+
};
|
|
42
|
+
export declare const json: <S extends Schema.Top>(schema: S) => Schema.Codec<unknown, unknown>;
|
|
43
|
+
export declare const payloadCodec: (rpc: Rpc.AnyWithProps) => Schema.Codec<unknown, unknown, never, never>;
|
|
44
|
+
export declare const exitCodec: (rpc: Rpc.AnyWithProps) => Schema.Codec<unknown, unknown, never, never>;
|
|
45
|
+
export declare const chunkCodec: (rpc: Rpc.AnyWithProps) => Schema.Codec<unknown, unknown, never, never>;
|
|
46
|
+
export declare const encode: (codec: Schema.Codec<unknown, unknown>, value: unknown) => Effect.Effect<unknown, never, never>;
|
|
47
|
+
export declare const decode: (codec: Schema.Codec<unknown, unknown>, value: unknown) => Effect.Effect<unknown, never, never>;
|
|
48
|
+
/**
|
|
49
|
+
* An RPC's exit, encoded. A stream's exit carries no value. An exit its
|
|
50
|
+
* schema can't encode (a defect that isn't JSON) is sent as a defect with
|
|
51
|
+
* its message.
|
|
52
|
+
*/
|
|
53
|
+
export declare const encodeExit: (rpc: Rpc.AnyWithProps, exit: Exit.Exit<unknown, unknown>) => Effect.Effect<unknown, never, never>;
|
|
54
|
+
/** `(type, id)` as one object name, length-prefixed like Effect's: `7:Counter` + id. */
|
|
55
|
+
export declare const entityObjectName: (type: string, id: string) => string;
|
|
56
|
+
export declare const parseEntityObjectName: (name: string) => {
|
|
57
|
+
type: string;
|
|
58
|
+
id: string;
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=Wire.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Wire.d.ts","sources":["../../src/internal/Wire.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,GAAG,EAAa,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,mEAAmE;AACnE,MAAM,WAAW,IAAI;IACnB,8DAA8D;IAC9D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAED,wDAAwD;AACxD,eAAO,MAAM,MAAM,oBAAoB,CAAC;AAExC,4EAA4E;AAC5E,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,0BAA0B,GAAG,kBAAkB,CAAC;IAC/E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;GAIG;AACH,MAAM,MAAM,KAAK,GACb;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAC1B;IAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAAE,GAChC;IAAE,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAElC,MAAM,MAAM,KAAK,GAAG,KAAK,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,CAAA;CAAE,CAAC;AAEvE,eAAO,MAAM,IAAI,GAAI,CAAC,SAAS,MAAM,CAAC,GAAG,UAAU,CAAC,KACT,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAE1E,eAAO,MAAM,YAAY,QAAS,GAAG,CAAC,YAAY,iDAA4B,CAAC;AAC/E,eAAO,MAAM,SAAS,QAAS,GAAG,CAAC,YAAY,iDAAyC,CAAC;AACzF,eAAO,MAAM,UAAU,QAAS,GAAG,CAAC,YAAY,iDACgD,CAAC;AAEjG,eAAO,MAAM,MAAM,UAAW,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,OAAO,yCACf,CAAC;AAC9D,eAAO,MAAM,MAAM,UAAW,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,OAAO,yCACf,CAAC;AAE9D;;;;GAIG;AACH,eAAO,MAAM,UAAU,QAAS,GAAG,CAAC,YAAY,QAAQ,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,yCAUhF,CAAC;AAEJ,wFAAwF;AACxF,eAAO,MAAM,gBAAgB,SAAU,MAAM,MAAM,MAAM,WAAkC,CAAC;AAE5F,eAAO,MAAM,qBAAqB,SAAU,MAAM;IAI9C,IAAI;IACJ,EAAE;CAEL,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What crosses between a caller and an entity's object: each call as JSON,
|
|
3
|
+
* its reply as JSON. A host's object RPC hides a thrown error's type, so
|
|
4
|
+
* failures of the object itself come back as data too.
|
|
5
|
+
*
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
import * as Effect from "effect/Effect";
|
|
9
|
+
import * as Exit from "effect/Exit";
|
|
10
|
+
import { Rpc, RpcSchema } from "effect/rpc";
|
|
11
|
+
import * as Schema from "effect/Schema";
|
|
12
|
+
/** A failure of the object itself, returned as data. */
|
|
13
|
+
export const DEFECT = "~cluster/defect";
|
|
14
|
+
export const json = (schema) => Schema.toCodecJson(schema);
|
|
15
|
+
export const payloadCodec = (rpc) => json(rpc.payloadSchema);
|
|
16
|
+
export const exitCodec = (rpc) => json(Rpc.exitSchema(rpc));
|
|
17
|
+
export const chunkCodec = (rpc) => json(RpcSchema.isStreamSchema(rpc.successSchema) ? rpc.successSchema.success : Schema.Unknown);
|
|
18
|
+
export const encode = (codec, value) => Schema.encodeUnknownEffect(codec)(value).pipe(Effect.orDie);
|
|
19
|
+
export const decode = (codec, value) => Schema.decodeUnknownEffect(codec)(value).pipe(Effect.orDie);
|
|
20
|
+
/**
|
|
21
|
+
* An RPC's exit, encoded. A stream's exit carries no value. An exit its
|
|
22
|
+
* schema can't encode (a defect that isn't JSON) is sent as a defect with
|
|
23
|
+
* its message.
|
|
24
|
+
*/
|
|
25
|
+
export const encodeExit = (rpc, exit) => Schema.encodeUnknownEffect(exitCodec(rpc))(RpcSchema.isStreamSchema(rpc.successSchema) ? Exit.asVoid(exit) : exit).pipe(Effect.catchCause(() => Schema.encodeUnknownEffect(exitCodec(rpc))(Exit.die(Exit.isFailure(exit) ? String(exit.cause) : "unencodable exit"))), Effect.orDie);
|
|
26
|
+
/** `(type, id)` as one object name, length-prefixed like Effect's: `7:Counter` + id. */
|
|
27
|
+
export const entityObjectName = (type, id) => `${type.length}:${type}${id}`;
|
|
28
|
+
export const parseEntityObjectName = (name) => {
|
|
29
|
+
const colon = name.indexOf(":");
|
|
30
|
+
const length = Number(name.slice(0, colon));
|
|
31
|
+
return {
|
|
32
|
+
type: name.slice(colon + 1, colon + 1 + length),
|
|
33
|
+
id: name.slice(colon + 1 + length),
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=Wire.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Wire.js","sources":["../../src/internal/Wire.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Layer from "effect/Layer";
|
|
3
|
+
import { Rpc, RpcGroup } from "effect/rpc";
|
|
4
|
+
import * as Schema from "effect/Schema";
|
|
5
|
+
import { Workflow, WorkflowEngine } from "effect/workflow";
|
|
6
|
+
import { type GatewayTarget } from "./Gateway.ts";
|
|
7
|
+
declare const WorkflowRpcs_base: RpcGroup.RpcGroup<Rpc.Rpc<"Workflow.Interrupt", Schema.Struct<{
|
|
8
|
+
workflow: Schema.String;
|
|
9
|
+
executionId: Schema.String;
|
|
10
|
+
}>, Schema.Void, Schema.Never, never, never> | Rpc.Rpc<"Workflow.Poll", Schema.Struct<{
|
|
11
|
+
workflow: Schema.String;
|
|
12
|
+
executionId: Schema.String;
|
|
13
|
+
}>, Schema.Struct<{
|
|
14
|
+
readonly state: Schema.Literals<readonly ["none", "suspended", "complete"]>;
|
|
15
|
+
readonly result: Schema.optional<Schema.String>;
|
|
16
|
+
}>, Schema.Never, never, never> | Rpc.Rpc<"Workflow.Signal", Schema.Struct<{
|
|
17
|
+
workflow: Schema.String;
|
|
18
|
+
executionId: Schema.String;
|
|
19
|
+
name: Schema.String;
|
|
20
|
+
exit: Schema.String;
|
|
21
|
+
}>, Schema.Void, Schema.Never, never, never> | Rpc.Rpc<"Workflow.Start", Schema.Struct<{
|
|
22
|
+
workflow: Schema.String;
|
|
23
|
+
executionId: Schema.String;
|
|
24
|
+
payload: Schema.Unknown;
|
|
25
|
+
}>, Schema.Void, Schema.Never, never, never>>;
|
|
26
|
+
export declare class WorkflowRpcs extends WorkflowRpcs_base {
|
|
27
|
+
}
|
|
28
|
+
/** The pool's side: each RPC on the pool's own engine, for the workflows they host. */
|
|
29
|
+
export declare const workflowHandlers: (workflows: ReadonlyMap<string, Workflow.Any>) => Layer.Layer<Rpc.Handler<"Workflow.Interrupt"> | Rpc.Handler<"Workflow.Poll"> | Rpc.Handler<"Workflow.Signal"> | Rpc.Handler<"Workflow.Start">, never, any>;
|
|
30
|
+
/**
|
|
31
|
+
* A caller's engine: starts and reads runs through the gateway of the
|
|
32
|
+
* pool that hosts each workflow. `route` returns that gateway.
|
|
33
|
+
*/
|
|
34
|
+
export declare const makeRemoteEngine: (route: (workflowName: string) => Effect.Effect<GatewayTarget>) => WorkflowEngine.WorkflowEngine["Service"];
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=WorkflowGateway.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkflowGateway.d.ts","sources":["../../src/internal/WorkflowGateway.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAIxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAEtC,OAAO,EAAE,GAAG,EAAkC,QAAQ,EAAoB,MAAM,YAAY,CAAC;AAC7F,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EAAmB,QAAQ,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAAgB,KAAK,aAAa,EAAgB,MAAM,cAAc,CAAC;;;;;;;;;;;;;;;;;;;;AAI9E,qBAAa,YAAa,SAAQ,iBAWjC;CAAG;AAMJ,uFAAuF;AACvF,eAAO,MAAM,gBAAgB,cAAe,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,CAAC,+JA+C1E,CAAC;AASJ;;;GAGG;AACH,eAAO,MAAM,gBAAgB,UACpB,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,KAC5D,cAAc,CAAC,cAAc,CAAC,SAAS,CA6EzC,CAAC"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How callers outside the cluster reach the workflows a pool hosts: four
|
|
3
|
+
* RPCs on the pool's gateway, served by the pool's own
|
|
4
|
+
* `ClusterWorkflowEngine`, and a `WorkflowEngine` for callers that sends
|
|
5
|
+
* them. Payloads, results and signals cross as JSON, encoded with the
|
|
6
|
+
* workflow's own schemas.
|
|
7
|
+
*
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
import { decodeExit, decodeResult, encodeExit, encodeResult, payloadCodec, } from "alchemy/WorkflowEncoding";
|
|
11
|
+
import * as Data from "effect/Data";
|
|
12
|
+
import * as Effect from "effect/Effect";
|
|
13
|
+
import * as FetchHttpClient from "effect/http/FetchHttpClient";
|
|
14
|
+
import * as HttpClient from "effect/http/HttpClient";
|
|
15
|
+
import * as HttpClientRequest from "effect/http/HttpClientRequest";
|
|
16
|
+
import * as Layer from "effect/Layer";
|
|
17
|
+
import * as Option from "effect/Option";
|
|
18
|
+
import { Rpc, RpcClient, RpcGroup, RpcSerialization } from "effect/rpc";
|
|
19
|
+
import * as Schema from "effect/Schema";
|
|
20
|
+
import { DurableDeferred, Workflow, WorkflowEngine } from "effect/workflow";
|
|
21
|
+
import { GATEWAY_PATH, gatewayFetch } from "./Gateway.js";
|
|
22
|
+
const Run = { workflow: Schema.String, executionId: Schema.String };
|
|
23
|
+
export class WorkflowRpcs extends RpcGroup.make(Rpc.make("Workflow.Start", { payload: { ...Run, payload: Schema.Unknown } }), Rpc.make("Workflow.Poll", {
|
|
24
|
+
payload: Run,
|
|
25
|
+
success: Schema.Struct({
|
|
26
|
+
state: Schema.Literals(["none", "suspended", "complete"]),
|
|
27
|
+
result: Schema.optional(Schema.String),
|
|
28
|
+
}),
|
|
29
|
+
}), Rpc.make("Workflow.Interrupt", { payload: Run }), Rpc.make("Workflow.Signal", { payload: { ...Run, name: Schema.String, exit: Schema.String } })) {
|
|
30
|
+
}
|
|
31
|
+
class UnknownWorkflow extends Data.TaggedError("Cluster.UnknownWorkflow") {
|
|
32
|
+
}
|
|
33
|
+
/** The pool's side: each RPC on the pool's own engine, for the workflows they host. */
|
|
34
|
+
export const workflowHandlers = (workflows) => WorkflowRpcs.toLayer(Effect.gen(function* () {
|
|
35
|
+
const engine = yield* WorkflowEngine.WorkflowEngine;
|
|
36
|
+
const find = (name) => {
|
|
37
|
+
const workflow = workflows.get(name);
|
|
38
|
+
return workflow === undefined
|
|
39
|
+
? Effect.die(new UnknownWorkflow({ workflow: name }))
|
|
40
|
+
: Effect.succeed(workflow);
|
|
41
|
+
};
|
|
42
|
+
return WorkflowRpcs.of({
|
|
43
|
+
"Workflow.Start": ({ workflow: name, executionId, payload }) => Effect.gen(function* () {
|
|
44
|
+
const workflow = yield* find(name);
|
|
45
|
+
const decoded = yield* Schema.decodeUnknownEffect(payloadCodec(workflow))(payload).pipe(Effect.orDie);
|
|
46
|
+
yield* engine.execute(workflow, {
|
|
47
|
+
executionId,
|
|
48
|
+
payload: decoded,
|
|
49
|
+
discard: true,
|
|
50
|
+
});
|
|
51
|
+
}).pipe(Effect.orDie),
|
|
52
|
+
"Workflow.Poll": ({ workflow: name, executionId }) => Effect.gen(function* () {
|
|
53
|
+
const workflow = yield* find(name);
|
|
54
|
+
const result = yield* engine.poll(workflow, executionId);
|
|
55
|
+
if (Option.isNone(result))
|
|
56
|
+
return { state: "none" };
|
|
57
|
+
if (result.value._tag === "Suspended")
|
|
58
|
+
return { state: "suspended" };
|
|
59
|
+
return {
|
|
60
|
+
state: "complete",
|
|
61
|
+
result: yield* encodeResult(workflow, result.value.exit),
|
|
62
|
+
};
|
|
63
|
+
}),
|
|
64
|
+
"Workflow.Interrupt": ({ workflow: name, executionId }) => Effect.flatMap(find(name), (workflow) => engine.interrupt(workflow, executionId)),
|
|
65
|
+
// The exit arrives encoded with the deferred's own schemas, so it is
|
|
66
|
+
// passed on through a deferred whose schemas leave it as it is.
|
|
67
|
+
"Workflow.Signal": ({ workflow, executionId, name, exit }) => Effect.flatMap(decodeExit(exit), (decoded) => engine.deferredDone(DurableDeferred.make(name, { success: Schema.Unknown, error: Schema.Unknown }), { workflowName: workflow, executionId, deferredName: name, exit: decoded })),
|
|
68
|
+
});
|
|
69
|
+
}));
|
|
70
|
+
/** A step only runs inside a run, and runs only run on the pool. */
|
|
71
|
+
class RunsOnPool extends Data.TaggedError("Cluster.RunsOnPool") {
|
|
72
|
+
}
|
|
73
|
+
const onPool = (operation) => Effect.die(new RunsOnPool({ operation }));
|
|
74
|
+
/**
|
|
75
|
+
* A caller's engine: starts and reads runs through the gateway of the
|
|
76
|
+
* pool that hosts each workflow. `route` returns that gateway.
|
|
77
|
+
*/
|
|
78
|
+
export const makeRemoteEngine = (route) => {
|
|
79
|
+
const call = (workflowName, use) => Effect.gen(function* () {
|
|
80
|
+
const target = yield* route(workflowName);
|
|
81
|
+
const protocol = RpcClient.layerProtocolHttp({
|
|
82
|
+
url: `${target.url.replace(/\/+$/, "")}${GATEWAY_PATH}`,
|
|
83
|
+
transformClient: HttpClient.mapRequest(HttpClientRequest.bearerToken(target.token)),
|
|
84
|
+
}).pipe(Layer.provide([FetchHttpClient.layer, RpcSerialization.layerJson]));
|
|
85
|
+
return yield* Effect.flatMap(RpcClient.make(WorkflowRpcs), use).pipe(Effect.scoped, Effect.provide(protocol), Effect.provideService(FetchHttpClient.Fetch, yield* gatewayFetch(target.service)));
|
|
86
|
+
}).pipe(Effect.orDie);
|
|
87
|
+
const poll = (workflow, executionId) => Effect.gen(function* () {
|
|
88
|
+
const reply = yield* call(workflow._tag, (client) => client["Workflow.Poll"]({ workflow: workflow._tag, executionId }));
|
|
89
|
+
if (reply.state === "none")
|
|
90
|
+
return Option.none();
|
|
91
|
+
if (reply.state === "suspended")
|
|
92
|
+
return Option.some(Workflow.Suspended.make({}));
|
|
93
|
+
return Option.some(yield* decodeResult(workflow, reply.result ?? "null"));
|
|
94
|
+
});
|
|
95
|
+
return WorkflowEngine.makeUnsafe({
|
|
96
|
+
// Workflows run on their runners; nothing registers here.
|
|
97
|
+
register: () => Effect.void,
|
|
98
|
+
execute: (workflow, options) => Effect.gen(function* () {
|
|
99
|
+
const payload = yield* Schema.encodeEffect(payloadCodec(workflow))(options.payload).pipe(Effect.orDie);
|
|
100
|
+
yield* call(workflow._tag, (client) => client["Workflow.Start"]({
|
|
101
|
+
workflow: workflow._tag,
|
|
102
|
+
executionId: options.executionId,
|
|
103
|
+
payload,
|
|
104
|
+
}));
|
|
105
|
+
if (options.discard)
|
|
106
|
+
return undefined;
|
|
107
|
+
return Option.getOrElse(yield* poll(workflow, options.executionId), () => Workflow.Suspended.make({}));
|
|
108
|
+
}),
|
|
109
|
+
poll,
|
|
110
|
+
interrupt: (workflow, executionId) => call(workflow._tag, (client) => client["Workflow.Interrupt"]({ workflow: workflow._tag, executionId })),
|
|
111
|
+
interruptUnsafe: (workflow, executionId) => call(workflow._tag, (client) => client["Workflow.Interrupt"]({ workflow: workflow._tag, executionId })),
|
|
112
|
+
resume: () => Effect.void,
|
|
113
|
+
activityExecute: () => onPool("Activity execution"),
|
|
114
|
+
deferredResult: () => onPool("DurableDeferred reads"),
|
|
115
|
+
deferredDone: ({ workflowName, executionId, deferredName, exit }) => Effect.flatMap(encodeExit(exit), (text) => call(workflowName, (client) => client["Workflow.Signal"]({
|
|
116
|
+
workflow: workflowName,
|
|
117
|
+
executionId,
|
|
118
|
+
name: deferredName,
|
|
119
|
+
exit: text,
|
|
120
|
+
}))),
|
|
121
|
+
scheduleClock: () => onPool("DurableClock scheduling"),
|
|
122
|
+
});
|
|
123
|
+
};
|
|
124
|
+
//# sourceMappingURL=WorkflowGateway.js.map
|