@effect/cluster 0.50.6 → 0.51.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/RunnerStorage/package.json +6 -0
- package/SqlRunnerStorage/package.json +6 -0
- package/dist/cjs/ClusterError.js +2 -24
- package/dist/cjs/ClusterError.js.map +1 -1
- package/dist/cjs/ClusterMetrics.js +13 -15
- package/dist/cjs/ClusterMetrics.js.map +1 -1
- package/dist/cjs/ClusterWorkflowEngine.js +41 -81
- package/dist/cjs/ClusterWorkflowEngine.js.map +1 -1
- package/dist/cjs/Entity.js.map +1 -1
- package/dist/cjs/EntityAddress.js +9 -1
- package/dist/cjs/EntityAddress.js.map +1 -1
- package/dist/cjs/EntityId.js +7 -1
- package/dist/cjs/EntityId.js.map +1 -1
- package/dist/cjs/EntityProxy.js +1 -1
- package/dist/cjs/EntityProxy.js.map +1 -1
- package/dist/cjs/HttpRunner.js +69 -43
- package/dist/cjs/HttpRunner.js.map +1 -1
- package/dist/cjs/MessageStorage.js +64 -16
- package/dist/cjs/MessageStorage.js.map +1 -1
- package/dist/cjs/Runner.js +3 -3
- package/dist/cjs/Runner.js.map +1 -1
- package/dist/cjs/RunnerAddress.js +7 -0
- package/dist/cjs/RunnerAddress.js.map +1 -1
- package/dist/cjs/RunnerHealth.js +91 -32
- package/dist/cjs/RunnerHealth.js.map +1 -1
- package/dist/cjs/RunnerServer.js +38 -24
- package/dist/cjs/RunnerServer.js.map +1 -1
- package/dist/cjs/RunnerStorage.js +100 -0
- package/dist/cjs/RunnerStorage.js.map +1 -0
- package/dist/cjs/Runners.js +18 -22
- package/dist/cjs/Runners.js.map +1 -1
- package/dist/cjs/ShardId.js +17 -7
- package/dist/cjs/ShardId.js.map +1 -1
- package/dist/cjs/Sharding.js +435 -318
- package/dist/cjs/Sharding.js.map +1 -1
- package/dist/cjs/ShardingConfig.js +10 -14
- package/dist/cjs/ShardingConfig.js.map +1 -1
- package/dist/cjs/Snowflake.js +1 -1
- package/dist/cjs/SocketRunner.js +1 -1
- package/dist/cjs/SocketRunner.js.map +1 -1
- package/dist/cjs/SqlMessageStorage.js +22 -28
- package/dist/cjs/SqlMessageStorage.js.map +1 -1
- package/dist/cjs/SqlRunnerStorage.js +378 -0
- package/dist/cjs/SqlRunnerStorage.js.map +1 -0
- package/dist/cjs/index.js +5 -15
- package/dist/cjs/internal/entityManager.js +40 -9
- package/dist/cjs/internal/entityManager.js.map +1 -1
- package/dist/dts/ClusterError.d.ts +0 -22
- package/dist/dts/ClusterError.d.ts.map +1 -1
- package/dist/dts/ClusterMetrics.d.ts +4 -14
- package/dist/dts/ClusterMetrics.d.ts.map +1 -1
- package/dist/dts/ClusterWorkflowEngine.d.ts.map +1 -1
- package/dist/dts/Entity.d.ts +2 -2
- package/dist/dts/Entity.d.ts.map +1 -1
- package/dist/dts/EntityAddress.d.ts +11 -0
- package/dist/dts/EntityAddress.d.ts.map +1 -1
- package/dist/dts/EntityId.d.ts +5 -0
- package/dist/dts/EntityId.d.ts.map +1 -1
- package/dist/dts/EntityProxy.d.ts +5 -6
- package/dist/dts/EntityProxy.d.ts.map +1 -1
- package/dist/dts/HttpRunner.d.ts +48 -25
- package/dist/dts/HttpRunner.d.ts.map +1 -1
- package/dist/dts/MessageStorage.d.ts +13 -5
- package/dist/dts/MessageStorage.d.ts.map +1 -1
- package/dist/dts/Runner.d.ts +4 -4
- package/dist/dts/Runner.d.ts.map +1 -1
- package/dist/dts/RunnerAddress.d.ts +5 -0
- package/dist/dts/RunnerAddress.d.ts.map +1 -1
- package/dist/dts/RunnerHealth.d.ts +24 -16
- package/dist/dts/RunnerHealth.d.ts.map +1 -1
- package/dist/dts/RunnerServer.d.ts +5 -4
- package/dist/dts/RunnerServer.d.ts.map +1 -1
- package/dist/dts/{ShardStorage.d.ts → RunnerStorage.d.ts} +41 -54
- package/dist/dts/RunnerStorage.d.ts.map +1 -0
- package/dist/dts/Runners.d.ts +15 -11
- package/dist/dts/Runners.d.ts.map +1 -1
- package/dist/dts/ShardId.d.ts +1 -1
- package/dist/dts/ShardId.d.ts.map +1 -1
- package/dist/dts/Sharding.d.ts +20 -10
- package/dist/dts/Sharding.d.ts.map +1 -1
- package/dist/dts/ShardingConfig.d.ts +40 -14
- package/dist/dts/ShardingConfig.d.ts.map +1 -1
- package/dist/dts/SocketRunner.d.ts +4 -3
- package/dist/dts/SocketRunner.d.ts.map +1 -1
- package/dist/dts/SqlMessageStorage.d.ts +2 -3
- package/dist/dts/SqlMessageStorage.d.ts.map +1 -1
- package/dist/dts/SqlRunnerStorage.d.ts +40 -0
- package/dist/dts/SqlRunnerStorage.d.ts.map +1 -0
- package/dist/dts/index.d.ts +4 -24
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/esm/ClusterError.js +0 -21
- package/dist/esm/ClusterError.js.map +1 -1
- package/dist/esm/ClusterMetrics.js +12 -14
- package/dist/esm/ClusterMetrics.js.map +1 -1
- package/dist/esm/ClusterWorkflowEngine.js +41 -81
- package/dist/esm/ClusterWorkflowEngine.js.map +1 -1
- package/dist/esm/Entity.js.map +1 -1
- package/dist/esm/EntityAddress.js +7 -0
- package/dist/esm/EntityAddress.js.map +1 -1
- package/dist/esm/EntityId.js +5 -0
- package/dist/esm/EntityId.js.map +1 -1
- package/dist/esm/EntityProxy.js +2 -2
- package/dist/esm/EntityProxy.js.map +1 -1
- package/dist/esm/HttpRunner.js +62 -39
- package/dist/esm/HttpRunner.js.map +1 -1
- package/dist/esm/MessageStorage.js +65 -17
- package/dist/esm/MessageStorage.js.map +1 -1
- package/dist/esm/Runner.js +3 -3
- package/dist/esm/Runner.js.map +1 -1
- package/dist/esm/RunnerAddress.js +7 -0
- package/dist/esm/RunnerAddress.js.map +1 -1
- package/dist/esm/RunnerHealth.js +88 -30
- package/dist/esm/RunnerHealth.js.map +1 -1
- package/dist/esm/RunnerServer.js +38 -24
- package/dist/esm/RunnerServer.js.map +1 -1
- package/dist/esm/RunnerStorage.js +90 -0
- package/dist/esm/RunnerStorage.js.map +1 -0
- package/dist/esm/Runners.js +19 -23
- package/dist/esm/Runners.js.map +1 -1
- package/dist/esm/ShardId.js +16 -6
- package/dist/esm/ShardId.js.map +1 -1
- package/dist/esm/Sharding.js +438 -321
- package/dist/esm/Sharding.js.map +1 -1
- package/dist/esm/ShardingConfig.js +10 -14
- package/dist/esm/ShardingConfig.js.map +1 -1
- package/dist/esm/Snowflake.js +1 -1
- package/dist/esm/SocketRunner.js +1 -1
- package/dist/esm/SocketRunner.js.map +1 -1
- package/dist/esm/SqlMessageStorage.js +22 -28
- package/dist/esm/SqlMessageStorage.js.map +1 -1
- package/dist/esm/SqlRunnerStorage.js +369 -0
- package/dist/esm/SqlRunnerStorage.js.map +1 -0
- package/dist/esm/index.js +4 -24
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal/entityManager.js +40 -9
- package/dist/esm/internal/entityManager.js.map +1 -1
- package/package.json +20 -60
- package/src/ClusterError.ts +0 -24
- package/src/ClusterMetrics.ts +12 -16
- package/src/ClusterWorkflowEngine.ts +38 -78
- package/src/Entity.ts +2 -7
- package/src/EntityAddress.ts +10 -0
- package/src/EntityId.ts +6 -0
- package/src/EntityProxy.ts +10 -10
- package/src/HttpRunner.ts +132 -67
- package/src/MessageStorage.ts +89 -24
- package/src/Runner.ts +4 -4
- package/src/RunnerAddress.ts +8 -0
- package/src/RunnerHealth.ts +119 -56
- package/src/RunnerServer.ts +64 -47
- package/src/RunnerStorage.ts +218 -0
- package/src/Runners.ts +32 -45
- package/src/ShardId.ts +14 -3
- package/src/Sharding.ts +548 -413
- package/src/ShardingConfig.ts +39 -31
- package/src/Snowflake.ts +1 -1
- package/src/SocketRunner.ts +6 -4
- package/src/SqlMessageStorage.ts +28 -30
- package/src/SqlRunnerStorage.ts +541 -0
- package/src/index.ts +4 -29
- package/src/internal/entityManager.ts +44 -10
- package/HttpCommon/package.json +0 -6
- package/HttpShardManager/package.json +0 -6
- package/ShardManager/package.json +0 -6
- package/ShardStorage/package.json +0 -6
- package/SocketShardManager/package.json +0 -6
- package/SqlShardStorage/package.json +0 -6
- package/SynchronizedClock/package.json +0 -6
- package/dist/cjs/HttpCommon.js +0 -48
- package/dist/cjs/HttpCommon.js.map +0 -1
- package/dist/cjs/HttpShardManager.js +0 -139
- package/dist/cjs/HttpShardManager.js.map +0 -1
- package/dist/cjs/ShardManager.js +0 -549
- package/dist/cjs/ShardManager.js.map +0 -1
- package/dist/cjs/ShardStorage.js +0 -151
- package/dist/cjs/ShardStorage.js.map +0 -1
- package/dist/cjs/SocketShardManager.js +0 -32
- package/dist/cjs/SocketShardManager.js.map +0 -1
- package/dist/cjs/SqlShardStorage.js +0 -253
- package/dist/cjs/SqlShardStorage.js.map +0 -1
- package/dist/cjs/SynchronizedClock.js +0 -65
- package/dist/cjs/SynchronizedClock.js.map +0 -1
- package/dist/cjs/internal/shardManager.js +0 -353
- package/dist/cjs/internal/shardManager.js.map +0 -1
- package/dist/dts/HttpCommon.d.ts +0 -25
- package/dist/dts/HttpCommon.d.ts.map +0 -1
- package/dist/dts/HttpShardManager.d.ts +0 -119
- package/dist/dts/HttpShardManager.d.ts.map +0 -1
- package/dist/dts/ShardManager.d.ts +0 -459
- package/dist/dts/ShardManager.d.ts.map +0 -1
- package/dist/dts/ShardStorage.d.ts.map +0 -1
- package/dist/dts/SocketShardManager.d.ts +0 -17
- package/dist/dts/SocketShardManager.d.ts.map +0 -1
- package/dist/dts/SqlShardStorage.d.ts +0 -38
- package/dist/dts/SqlShardStorage.d.ts.map +0 -1
- package/dist/dts/SynchronizedClock.d.ts +0 -19
- package/dist/dts/SynchronizedClock.d.ts.map +0 -1
- package/dist/dts/internal/shardManager.d.ts +0 -2
- package/dist/dts/internal/shardManager.d.ts.map +0 -1
- package/dist/esm/HttpCommon.js +0 -38
- package/dist/esm/HttpCommon.js.map +0 -1
- package/dist/esm/HttpShardManager.js +0 -128
- package/dist/esm/HttpShardManager.js.map +0 -1
- package/dist/esm/ShardManager.js +0 -535
- package/dist/esm/ShardManager.js.map +0 -1
- package/dist/esm/ShardStorage.js +0 -141
- package/dist/esm/ShardStorage.js.map +0 -1
- package/dist/esm/SocketShardManager.js +0 -24
- package/dist/esm/SocketShardManager.js.map +0 -1
- package/dist/esm/SqlShardStorage.js +0 -244
- package/dist/esm/SqlShardStorage.js.map +0 -1
- package/dist/esm/SynchronizedClock.js +0 -57
- package/dist/esm/SynchronizedClock.js.map +0 -1
- package/dist/esm/internal/shardManager.js +0 -342
- package/dist/esm/internal/shardManager.js.map +0 -1
- package/src/HttpCommon.ts +0 -73
- package/src/HttpShardManager.ts +0 -273
- package/src/ShardManager.ts +0 -823
- package/src/ShardStorage.ts +0 -297
- package/src/SocketShardManager.ts +0 -48
- package/src/SqlShardStorage.ts +0 -329
- package/src/SynchronizedClock.ts +0 -82
- package/src/internal/shardManager.ts +0 -412
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 1.0.0
|
|
3
|
+
*/
|
|
4
|
+
import * as SqlClient from "@effect/sql/SqlClient";
|
|
5
|
+
import * as Arr from "effect/Array";
|
|
6
|
+
import * as Duration from "effect/Duration";
|
|
7
|
+
import * as Effect from "effect/Effect";
|
|
8
|
+
import * as Layer from "effect/Layer";
|
|
9
|
+
import * as ScopedRef from "effect/ScopedRef";
|
|
10
|
+
import { PersistenceError } from "./ClusterError.js";
|
|
11
|
+
import * as RunnerStorage from "./RunnerStorage.js";
|
|
12
|
+
import * as ShardId from "./ShardId.js";
|
|
13
|
+
import * as ShardingConfig from "./ShardingConfig.js";
|
|
14
|
+
const withTracerDisabled = /*#__PURE__*/Effect.withTracerEnabled(false);
|
|
15
|
+
/**
|
|
16
|
+
* @since 1.0.0
|
|
17
|
+
* @category Constructors
|
|
18
|
+
*/
|
|
19
|
+
export const make = /*#__PURE__*/Effect.fnUntraced(function* (options) {
|
|
20
|
+
const config = yield* ShardingConfig.ShardingConfig;
|
|
21
|
+
const sql = (yield* SqlClient.SqlClient).withoutTransforms();
|
|
22
|
+
const prefix = options?.prefix ?? "cluster";
|
|
23
|
+
const table = name => `${prefix}_${name}`;
|
|
24
|
+
const lockConnRef = yield* sql.onDialectOrElse({
|
|
25
|
+
sqlite: () => Effect.void,
|
|
26
|
+
orElse: () => ScopedRef.fromAcquire(sql.reserve)
|
|
27
|
+
});
|
|
28
|
+
const runnersTable = table("runners");
|
|
29
|
+
const runnersTableSql = sql(runnersTable);
|
|
30
|
+
// Migrate old tables if they exist
|
|
31
|
+
// TODO: Remove in next major version
|
|
32
|
+
const hasOldTables = yield* sql`SELECT shard_id FROM ${sql(table("shards"))} LIMIT 1`.pipe(Effect.isSuccess);
|
|
33
|
+
if (hasOldTables) {
|
|
34
|
+
yield* sql`DROP TABLE ${sql(table("shards"))}`.pipe(Effect.ignore);
|
|
35
|
+
yield* sql`DROP TABLE ${runnersTableSql}`.pipe(Effect.ignore);
|
|
36
|
+
}
|
|
37
|
+
yield* sql.onDialectOrElse({
|
|
38
|
+
mssql: () => sql`
|
|
39
|
+
IF OBJECT_ID(N'${runnersTableSql}', N'U') IS NULL
|
|
40
|
+
CREATE TABLE ${runnersTableSql} (
|
|
41
|
+
machine_id INT IDENTITY PRIMARY KEY,
|
|
42
|
+
address VARCHAR(255) NOT NULL,
|
|
43
|
+
runner TEXT NOT NULL,
|
|
44
|
+
healthy BIT NOT NULL DEFAULT 1,
|
|
45
|
+
last_heartbeat DATETIME NOT NULL DEFAULT GETDATE(),
|
|
46
|
+
UNIQUE(address)
|
|
47
|
+
)
|
|
48
|
+
`,
|
|
49
|
+
mysql: () => sql`
|
|
50
|
+
CREATE TABLE IF NOT EXISTS ${runnersTableSql} (
|
|
51
|
+
machine_id INT AUTO_INCREMENT PRIMARY KEY,
|
|
52
|
+
address VARCHAR(255) NOT NULL,
|
|
53
|
+
runner TEXT NOT NULL,
|
|
54
|
+
healthy BOOLEAN NOT NULL DEFAULT TRUE,
|
|
55
|
+
last_heartbeat DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
56
|
+
UNIQUE(address)
|
|
57
|
+
)
|
|
58
|
+
`,
|
|
59
|
+
pg: () => sql`
|
|
60
|
+
CREATE TABLE IF NOT EXISTS ${runnersTableSql} (
|
|
61
|
+
machine_id SERIAL PRIMARY KEY,
|
|
62
|
+
address VARCHAR(255) NOT NULL,
|
|
63
|
+
runner TEXT NOT NULL,
|
|
64
|
+
healthy BOOLEAN NOT NULL DEFAULT TRUE,
|
|
65
|
+
last_heartbeat TIMESTAMP NOT NULL DEFAULT NOW(),
|
|
66
|
+
UNIQUE(address)
|
|
67
|
+
)
|
|
68
|
+
`,
|
|
69
|
+
orElse: () =>
|
|
70
|
+
// sqlite
|
|
71
|
+
sql`
|
|
72
|
+
CREATE TABLE IF NOT EXISTS ${runnersTableSql} (
|
|
73
|
+
machine_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
74
|
+
address TEXT NOT NULL,
|
|
75
|
+
runner TEXT NOT NULL,
|
|
76
|
+
healthy INTEGER NOT NULL DEFAULT 1,
|
|
77
|
+
last_heartbeat DATETIME NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
|
78
|
+
UNIQUE(address)
|
|
79
|
+
)
|
|
80
|
+
`
|
|
81
|
+
});
|
|
82
|
+
const locksTable = table("locks");
|
|
83
|
+
const locksTableSql = sql(locksTable);
|
|
84
|
+
yield* sql.onDialectOrElse({
|
|
85
|
+
mssql: () => sql`
|
|
86
|
+
IF OBJECT_ID(N'${locksTableSql}', N'U') IS NULL
|
|
87
|
+
CREATE TABLE ${locksTableSql} (
|
|
88
|
+
shard_id VARCHAR(50) PRIMARY KEY,
|
|
89
|
+
address VARCHAR(255) NOT NULL,
|
|
90
|
+
acquired_at DATETIME NOT NULL
|
|
91
|
+
)
|
|
92
|
+
`,
|
|
93
|
+
mysql: () => Effect.void,
|
|
94
|
+
pg: () => Effect.void,
|
|
95
|
+
orElse: () =>
|
|
96
|
+
// sqlite
|
|
97
|
+
sql`
|
|
98
|
+
CREATE TABLE IF NOT EXISTS ${locksTableSql} (
|
|
99
|
+
shard_id TEXT PRIMARY KEY,
|
|
100
|
+
address TEXT NOT NULL,
|
|
101
|
+
acquired_at DATETIME NOT NULL
|
|
102
|
+
)
|
|
103
|
+
`
|
|
104
|
+
});
|
|
105
|
+
const sqlNowString = sql.onDialectOrElse({
|
|
106
|
+
pg: () => "NOW()",
|
|
107
|
+
mysql: () => "NOW()",
|
|
108
|
+
mssql: () => "GETDATE()",
|
|
109
|
+
orElse: () => "CURRENT_TIMESTAMP"
|
|
110
|
+
});
|
|
111
|
+
const sqlNow = sql.literal(sqlNowString);
|
|
112
|
+
const expiresSeconds = sql.literal(Math.ceil(Duration.toSeconds(config.shardLockExpiration)).toString());
|
|
113
|
+
const lockExpiresAt = sql.onDialectOrElse({
|
|
114
|
+
pg: () => sql`${sqlNow} - INTERVAL '${expiresSeconds} seconds'`,
|
|
115
|
+
mysql: () => sql`DATE_SUB(${sqlNow}, INTERVAL ${expiresSeconds} SECOND)`,
|
|
116
|
+
mssql: () => sql`DATEADD(SECOND, -${expiresSeconds}, ${sqlNow})`,
|
|
117
|
+
orElse: () => sql`datetime(${sqlNow}, '-${expiresSeconds} seconds')`
|
|
118
|
+
});
|
|
119
|
+
const encodeBoolean = sql.onDialectOrElse({
|
|
120
|
+
mssql: () => b => b ? 1 : 0,
|
|
121
|
+
sqlite: () => b => b ? 1 : 0,
|
|
122
|
+
orElse: () => b => b
|
|
123
|
+
});
|
|
124
|
+
// Upsert runner and return machine_id
|
|
125
|
+
const insertRunner = sql.onDialectOrElse({
|
|
126
|
+
mssql: () => (address, runner, healthy) => sql`
|
|
127
|
+
MERGE ${runnersTableSql} AS target
|
|
128
|
+
USING (SELECT ${address} AS address, ${runner} AS runner, ${sqlNow} AS last_heartbeat, ${encodeBoolean(healthy)} AS healthy) AS source
|
|
129
|
+
ON target.address = source.address
|
|
130
|
+
WHEN MATCHED THEN
|
|
131
|
+
UPDATE SET runner = source.runner, last_heartbeat = source.last_heartbeat, healthy = source.healthy
|
|
132
|
+
WHEN NOT MATCHED THEN
|
|
133
|
+
INSERT (address, runner, last_heartbeat, healthy)
|
|
134
|
+
VALUES (source.address, source.runner, source.last_heartbeat, source.healthy)
|
|
135
|
+
OUTPUT INSERTED.machine_id;
|
|
136
|
+
`.values,
|
|
137
|
+
mysql: () => (address, runner, healthy) => sql`
|
|
138
|
+
INSERT INTO ${runnersTableSql} (address, runner, last_heartbeat, healthy)
|
|
139
|
+
VALUES (${address}, ${runner}, ${sqlNow}, ${healthy})
|
|
140
|
+
ON DUPLICATE KEY UPDATE
|
|
141
|
+
runner = VALUES(runner),
|
|
142
|
+
last_heartbeat = VALUES(last_heartbeat),
|
|
143
|
+
healthy = VALUES(healthy);
|
|
144
|
+
SELECT machine_id FROM ${runnersTableSql} WHERE address = ${address};
|
|
145
|
+
`.unprepared.pipe(Effect.map(results => [[results[1][0].machine_id]])),
|
|
146
|
+
pg: () => (address, runner, healthy) => sql`
|
|
147
|
+
INSERT INTO ${runnersTableSql} (address, runner, last_heartbeat, healthy)
|
|
148
|
+
VALUES (${address}, ${runner}, ${sqlNow}, ${healthy})
|
|
149
|
+
ON CONFLICT (address) DO UPDATE
|
|
150
|
+
SET runner = EXCLUDED.runner,
|
|
151
|
+
last_heartbeat = EXCLUDED.last_heartbeat,
|
|
152
|
+
healthy = EXCLUDED.healthy
|
|
153
|
+
RETURNING machine_id
|
|
154
|
+
`.values,
|
|
155
|
+
orElse: () => (address, runner, healthy) =>
|
|
156
|
+
// sqlite
|
|
157
|
+
sql`
|
|
158
|
+
INSERT INTO ${runnersTableSql} (address, runner, last_heartbeat, healthy)
|
|
159
|
+
VALUES (${address}, ${runner}, ${sqlNow}, ${encodeBoolean(healthy)})
|
|
160
|
+
ON CONFLICT(address) DO UPDATE SET
|
|
161
|
+
runner = excluded.runner,
|
|
162
|
+
last_heartbeat = excluded.last_heartbeat,
|
|
163
|
+
healthy = excluded.healthy
|
|
164
|
+
RETURNING machine_id;
|
|
165
|
+
`.values
|
|
166
|
+
});
|
|
167
|
+
const execWithLockConn = effect => {
|
|
168
|
+
if (!lockConnRef) return effect;
|
|
169
|
+
const [query, params] = effect.compile();
|
|
170
|
+
return ScopedRef.get(lockConnRef).pipe(Effect.flatMap(conn => conn.executeRaw(query, params)), Effect.onError(() => resetLockConn));
|
|
171
|
+
};
|
|
172
|
+
const execWithLockConnValues = effect => {
|
|
173
|
+
if (!lockConnRef) return effect.values;
|
|
174
|
+
const [query, params] = effect.compile();
|
|
175
|
+
return ScopedRef.get(lockConnRef).pipe(Effect.flatMap(conn => conn.executeValues(query, params)), Effect.onError(() => resetLockConn));
|
|
176
|
+
};
|
|
177
|
+
const resetLockConn = sql.onDialectOrElse({
|
|
178
|
+
pg: () => Effect.gen(function* () {
|
|
179
|
+
const conn = yield* ScopedRef.get(lockConnRef);
|
|
180
|
+
yield* Effect.ignore(conn.executeRaw("SELECT pg_advisory_unlock_all()", []));
|
|
181
|
+
yield* Effect.orDie(ScopedRef.set(lockConnRef, sql.reserve));
|
|
182
|
+
}),
|
|
183
|
+
mysql: () => Effect.gen(function* () {
|
|
184
|
+
const conn = yield* ScopedRef.get(lockConnRef);
|
|
185
|
+
yield* Effect.ignore(conn.executeRaw("SELECT RELEASE_ALL_LOCKS()", []));
|
|
186
|
+
yield* Effect.orDie(ScopedRef.set(lockConnRef, sql.reserve));
|
|
187
|
+
}),
|
|
188
|
+
orElse: () => Effect.void
|
|
189
|
+
});
|
|
190
|
+
const acquireLock = sql.onDialectOrElse({
|
|
191
|
+
pg: () => Effect.fnUntraced(function* (_address, shardIds) {
|
|
192
|
+
const conn = yield* ScopedRef.get(lockConnRef);
|
|
193
|
+
const acquiredShardIds = [];
|
|
194
|
+
const toAcquire = new Map(shardIds.map(shardId => [lockNumbers.get(shardId), shardId]));
|
|
195
|
+
const takenLocks = yield* conn.executeValues(`SELECT objid FROM pg_locks WHERE locktype = 'advisory' AND granted = true AND pid = pg_backend_pid() ORDER BY objid`, []);
|
|
196
|
+
for (let i = 0; i < takenLocks.length; i++) {
|
|
197
|
+
const lockNum = takenLocks[i][0];
|
|
198
|
+
acquiredShardIds.push(lockNumbersReverse.get(lockNum));
|
|
199
|
+
toAcquire.delete(lockNum);
|
|
200
|
+
}
|
|
201
|
+
if (toAcquire.size === 0) {
|
|
202
|
+
return acquiredShardIds;
|
|
203
|
+
}
|
|
204
|
+
const results = (yield* conn.executeUnprepared(`SELECT ${pgLocks(toAcquire)}`, [], undefined))[0];
|
|
205
|
+
for (const shardId in results) {
|
|
206
|
+
if (results[shardId]) {
|
|
207
|
+
acquiredShardIds.push(shardId);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return acquiredShardIds;
|
|
211
|
+
}, Effect.onError(() => resetLockConn)),
|
|
212
|
+
mysql: () => Effect.fnUntraced(function* (_address, shardIds) {
|
|
213
|
+
const conn = yield* ScopedRef.get(lockConnRef);
|
|
214
|
+
const takenLocks = (yield* conn.executeUnprepared(`SELECT ${allMySqlTakenLocks}`, [], undefined))[0];
|
|
215
|
+
const acquiredShardIds = [];
|
|
216
|
+
const toAcquire = [];
|
|
217
|
+
for (const shardId in takenLocks) {
|
|
218
|
+
if (takenLocks[shardId] === 1) {
|
|
219
|
+
acquiredShardIds.push(shardId);
|
|
220
|
+
} else if (shardIds.includes(shardId)) {
|
|
221
|
+
toAcquire.push(shardId);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (toAcquire.length === 0) {
|
|
225
|
+
return acquiredShardIds;
|
|
226
|
+
}
|
|
227
|
+
const results = (yield* conn.executeUnprepared(`SELECT ${mysqlLocks(toAcquire)}`, [], undefined))[0];
|
|
228
|
+
for (const shardId in results) {
|
|
229
|
+
if (results[shardId] === 1) {
|
|
230
|
+
acquiredShardIds.push(shardId);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return acquiredShardIds;
|
|
234
|
+
}, Effect.onError(() => resetLockConn)),
|
|
235
|
+
mssql: () => (address, shardIds) => {
|
|
236
|
+
const values = shardIds.map(shardId => sql`(${stringLiteral(shardId)}, ${stringLiteral(address)}, ${sqlNow})`);
|
|
237
|
+
return sql`
|
|
238
|
+
MERGE ${locksTableSql} WITH (HOLDLOCK) AS target
|
|
239
|
+
USING (SELECT * FROM (VALUES ${sql.csv(values)})) AS source (shard_id, address, acquired_at)
|
|
240
|
+
ON target.shard_id = source.shard_id
|
|
241
|
+
WHEN MATCHED AND (target.address = source.address OR DATEDIFF(SECOND, target.acquired_at, ${sqlNow}) > ${expiresSeconds}) THEN
|
|
242
|
+
UPDATE SET address = source.address, acquired_at = source.acquired_at
|
|
243
|
+
WHEN NOT MATCHED THEN
|
|
244
|
+
INSERT (shard_id, address, acquired_at)
|
|
245
|
+
VALUES (source.shard_id, source.address, source.acquired_at);
|
|
246
|
+
`.pipe(Effect.andThen(acquiredLocks(address, shardIds)), sql.withTransaction);
|
|
247
|
+
},
|
|
248
|
+
orElse: () => (address, shardIds) => {
|
|
249
|
+
const values = shardIds.map(shardId => sql`(${stringLiteral(shardId)}, ${stringLiteral(address)}, ${sqlNow})`);
|
|
250
|
+
return sql`
|
|
251
|
+
WITH source(shard_id, address, acquired_at) AS (VALUES ${sql.csv(values)})
|
|
252
|
+
INSERT INTO ${locksTableSql} (shard_id, address, acquired_at)
|
|
253
|
+
SELECT source.shard_id, source.address, source.acquired_at
|
|
254
|
+
FROM source
|
|
255
|
+
WHERE NOT EXISTS (
|
|
256
|
+
SELECT 1 FROM ${locksTableSql}
|
|
257
|
+
WHERE shard_id = source.shard_id
|
|
258
|
+
AND address != ${address}
|
|
259
|
+
AND (strftime('%s', ${sqlNow}) - strftime('%s', acquired_at)) <= ${expiresSeconds}
|
|
260
|
+
)
|
|
261
|
+
ON CONFLICT(shard_id) DO UPDATE
|
|
262
|
+
SET address = ${address}, acquired_at = ${sqlNow}
|
|
263
|
+
`.pipe(Effect.andThen(acquiredLocks(address, shardIds)), sql.withTransaction);
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
const lockNumbers = new Map();
|
|
267
|
+
const lockNumbersReverse = new Map();
|
|
268
|
+
for (let i = 0; i < config.shardGroups.length; i++) {
|
|
269
|
+
const group = config.shardGroups[i];
|
|
270
|
+
const base = (i + 1) * 1000000;
|
|
271
|
+
for (let shard = 1; shard <= config.shardsPerGroup; shard++) {
|
|
272
|
+
const shardId = ShardId.make(group, shard).toString();
|
|
273
|
+
const lockNum = base + shard;
|
|
274
|
+
lockNumbers.set(shardId, lockNum);
|
|
275
|
+
lockNumbersReverse.set(lockNum, shardId);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
const lockNames = new Map();
|
|
279
|
+
const lockNamesReverse = new Map();
|
|
280
|
+
for (let i = 0; i < config.shardGroups.length; i++) {
|
|
281
|
+
const group = config.shardGroups[i];
|
|
282
|
+
for (let shard = 1; shard <= config.shardsPerGroup; shard++) {
|
|
283
|
+
const shardId = ShardId.make(group, shard).toString();
|
|
284
|
+
const lockName = `${prefix}.${shardId}`;
|
|
285
|
+
lockNames.set(shardId, lockName);
|
|
286
|
+
lockNamesReverse.set(lockName, shardId);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
const pgLocks = shardIdsMap => Array.from(shardIdsMap.entries(), ([lockNum, shardId]) => `pg_try_advisory_lock(${lockNum}) AS "${shardId}"`).join(", ");
|
|
290
|
+
const mysqlLocks = shardIds => shardIds.map(shardId => `GET_LOCK('${lockNames.get(shardId)}', 0) AS "${shardId}"`).join(", ");
|
|
291
|
+
const allMySqlTakenLocks = Array.from(lockNames.entries(), ([shardId, lockName]) => `IS_USED_LOCK('${lockName}') = CONNECTION_ID() AS "${shardId}"`).join(", ");
|
|
292
|
+
const acquiredLocks = (address, shardIds) => sql`
|
|
293
|
+
SELECT shard_id FROM ${sql(locksTable)}
|
|
294
|
+
WHERE address = ${address}
|
|
295
|
+
AND acquired_at >= ${lockExpiresAt}
|
|
296
|
+
AND shard_id IN ${stringLiteralArr(shardIds)}
|
|
297
|
+
`.values.pipe(Effect.map(rows => rows.map(row => row[0])));
|
|
298
|
+
const wrapString = sql.onDialectOrElse({
|
|
299
|
+
mssql: () => s => `N'${s}'`,
|
|
300
|
+
orElse: () => s => `'${s}'`
|
|
301
|
+
});
|
|
302
|
+
const stringLiteral = s => sql.literal(wrapString(s));
|
|
303
|
+
const stringLiteralArr = arr => sql.literal(`(${arr.map(wrapString).join(",")})`);
|
|
304
|
+
const refreshShards = sql.onDialectOrElse({
|
|
305
|
+
pg: () => acquireLock,
|
|
306
|
+
mysql: () => acquireLock,
|
|
307
|
+
mssql: () => (address, shardIds) => sql`
|
|
308
|
+
UPDATE ${locksTableSql}
|
|
309
|
+
SET acquired_at = ${sqlNow}
|
|
310
|
+
OUTPUT inserted.shard_id
|
|
311
|
+
WHERE address = ${address} AND shard_id IN ${stringLiteralArr(shardIds)}
|
|
312
|
+
`.pipe(execWithLockConnValues, Effect.map(rows => rows.map(row => row[0]))),
|
|
313
|
+
orElse: () => (address, shardIds) => sql`
|
|
314
|
+
UPDATE ${locksTableSql}
|
|
315
|
+
SET acquired_at = ${sqlNow}
|
|
316
|
+
WHERE address = ${address} AND shard_id IN ${stringLiteralArr(shardIds)}
|
|
317
|
+
RETURNING shard_id
|
|
318
|
+
`.pipe(execWithLockConnValues, Effect.map(rows => rows.map(row => row[0])))
|
|
319
|
+
});
|
|
320
|
+
return RunnerStorage.makeEncoded({
|
|
321
|
+
getRunners: sql`SELECT runner, healthy FROM ${runnersTableSql} WHERE last_heartbeat > ${lockExpiresAt}`.values.pipe(PersistenceError.refail, Effect.map(Arr.map(([runner, healthy]) => [String(runner), Boolean(healthy)])), withTracerDisabled),
|
|
322
|
+
register: (address, runner, healthy) => insertRunner(address, runner, healthy).pipe(Effect.map(rows => Number(rows[0][0])), PersistenceError.refail, withTracerDisabled),
|
|
323
|
+
unregister: address => sql`DELETE FROM ${runnersTableSql} WHERE address = ${address} OR last_heartbeat < ${lockExpiresAt}`.pipe(Effect.asVoid, PersistenceError.refail, withTracerDisabled),
|
|
324
|
+
setRunnerHealth: (address, healthy) => sql`UPDATE ${runnersTableSql} SET healthy = ${encodeBoolean(healthy)} WHERE address = ${address}`.pipe(Effect.asVoid, PersistenceError.refail, withTracerDisabled),
|
|
325
|
+
acquire: (address, shardIds) => acquireLock(address, shardIds).pipe(PersistenceError.refail, withTracerDisabled),
|
|
326
|
+
refresh: (address, shardIds) => sql`UPDATE ${runnersTableSql} SET last_heartbeat = ${sqlNow} WHERE address = ${address}`.pipe(execWithLockConn, shardIds.length > 0 ? Effect.andThen(refreshShards(address, shardIds)) : Effect.as([]), PersistenceError.refail),
|
|
327
|
+
release: sql.onDialectOrElse({
|
|
328
|
+
pg: () => Effect.fnUntraced(function* (_address, shardId) {
|
|
329
|
+
const lockNum = lockNumbers.get(shardId);
|
|
330
|
+
const conn = yield* ScopedRef.get(lockConnRef);
|
|
331
|
+
const release = conn.executeRaw(`SELECT pg_advisory_unlock(${lockNum})`, []);
|
|
332
|
+
const check = conn.executeValues(`SELECT 1 FROM pg_locks WHERE locktype = 'advisory' AND granted = true AND pid = pg_backend_pid() AND objid = ${lockNum}`, []);
|
|
333
|
+
while (true) {
|
|
334
|
+
yield* release;
|
|
335
|
+
const takenLocks = yield* check;
|
|
336
|
+
if (takenLocks.length === 0) return;
|
|
337
|
+
}
|
|
338
|
+
}, Effect.onError(() => resetLockConn), Effect.asVoid, PersistenceError.refail, withTracerDisabled),
|
|
339
|
+
mysql: () => Effect.fnUntraced(function* (_address, shardId) {
|
|
340
|
+
const conn = yield* ScopedRef.get(lockConnRef);
|
|
341
|
+
const lockName = lockNames.get(shardId);
|
|
342
|
+
const release = conn.executeRaw(`SELECT RELEASE_LOCK('${lockName}')`, []);
|
|
343
|
+
const check = conn.executeValues(`SELECT IS_USED_LOCK('${lockName}') = CONNECTION_ID() AS is_taken`, []);
|
|
344
|
+
while (true) {
|
|
345
|
+
yield* release;
|
|
346
|
+
const takenLocks = yield* check;
|
|
347
|
+
if (takenLocks.length === 0 || takenLocks[0][0] !== 1) return;
|
|
348
|
+
}
|
|
349
|
+
}, Effect.onError(() => resetLockConn), Effect.asVoid, PersistenceError.refail, withTracerDisabled),
|
|
350
|
+
orElse: () => (address, shardId) => sql`DELETE FROM ${locksTableSql} WHERE address = ${address} AND shard_id = ${shardId}`.pipe(PersistenceError.refail, withTracerDisabled)
|
|
351
|
+
}),
|
|
352
|
+
releaseAll: sql.onDialectOrElse({
|
|
353
|
+
pg: () => _address => sql`SELECT pg_advisory_unlock_all()`.pipe(execWithLockConn, Effect.asVoid, PersistenceError.refail, withTracerDisabled),
|
|
354
|
+
mysql: () => _address => sql`SELECT RELEASE_ALL_LOCKS()`.pipe(execWithLockConn, Effect.asVoid, PersistenceError.refail, withTracerDisabled),
|
|
355
|
+
orElse: () => address => sql`DELETE FROM ${locksTableSql} WHERE address = ${address}`.pipe(PersistenceError.refail, withTracerDisabled)
|
|
356
|
+
})
|
|
357
|
+
});
|
|
358
|
+
}, withTracerDisabled);
|
|
359
|
+
/**
|
|
360
|
+
* @since 1.0.0
|
|
361
|
+
* @category Layers
|
|
362
|
+
*/
|
|
363
|
+
export const layer = /*#__PURE__*/Layer.scoped(RunnerStorage.RunnerStorage)(/*#__PURE__*/make({}));
|
|
364
|
+
/**
|
|
365
|
+
* @since 1.0.0
|
|
366
|
+
* @category Layers
|
|
367
|
+
*/
|
|
368
|
+
export const layerWith = options => Layer.scoped(RunnerStorage.RunnerStorage)(make(options));
|
|
369
|
+
//# sourceMappingURL=SqlRunnerStorage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SqlRunnerStorage.js","names":["SqlClient","Arr","Duration","Effect","Layer","ScopedRef","PersistenceError","RunnerStorage","ShardId","ShardingConfig","withTracerDisabled","withTracerEnabled","make","fnUntraced","options","config","sql","withoutTransforms","prefix","table","name","lockConnRef","onDialectOrElse","sqlite","void","orElse","fromAcquire","reserve","runnersTable","runnersTableSql","hasOldTables","pipe","isSuccess","ignore","mssql","mysql","pg","locksTable","locksTableSql","sqlNowString","sqlNow","literal","expiresSeconds","Math","ceil","toSeconds","shardLockExpiration","toString","lockExpiresAt","encodeBoolean","b","insertRunner","address","runner","healthy","values","unprepared","map","results","machine_id","execWithLockConn","effect","query","params","compile","get","flatMap","conn","executeRaw","onError","resetLockConn","execWithLockConnValues","executeValues","gen","orDie","set","acquireLock","_address","shardIds","acquiredShardIds","toAcquire","Map","shardId","lockNumbers","takenLocks","i","length","lockNum","push","lockNumbersReverse","delete","size","executeUnprepared","pgLocks","undefined","allMySqlTakenLocks","includes","mysqlLocks","stringLiteral","csv","andThen","acquiredLocks","withTransaction","shardGroups","group","base","shard","shardsPerGroup","lockNames","lockNamesReverse","lockName","shardIdsMap","Array","from","entries","join","stringLiteralArr","rows","row","wrapString","s","arr","refreshShards","makeEncoded","getRunners","refail","String","Boolean","register","Number","unregister","asVoid","setRunnerHealth","acquire","refresh","as","release","check","releaseAll","layer","scoped","layerWith"],"sources":["../../src/SqlRunnerStorage.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
|
package/dist/esm/index.js
CHANGED
|
@@ -50,18 +50,10 @@ export * as EntityType from "./EntityType.js";
|
|
|
50
50
|
* @since 1.0.0
|
|
51
51
|
*/
|
|
52
52
|
export * as Envelope from "./Envelope.js";
|
|
53
|
-
/**
|
|
54
|
-
* @since 1.0.0
|
|
55
|
-
*/
|
|
56
|
-
export * as HttpCommon from "./HttpCommon.js";
|
|
57
53
|
/**
|
|
58
54
|
* @since 1.0.0
|
|
59
55
|
*/
|
|
60
56
|
export * as HttpRunner from "./HttpRunner.js";
|
|
61
|
-
/**
|
|
62
|
-
* @since 1.0.0
|
|
63
|
-
*/
|
|
64
|
-
export * as HttpShardManager from "./HttpShardManager.js";
|
|
65
57
|
/**
|
|
66
58
|
* @since 1.0.0
|
|
67
59
|
*/
|
|
@@ -97,19 +89,15 @@ export * as RunnerServer from "./RunnerServer.js";
|
|
|
97
89
|
/**
|
|
98
90
|
* @since 1.0.0
|
|
99
91
|
*/
|
|
100
|
-
export * as
|
|
92
|
+
export * as RunnerStorage from "./RunnerStorage.js";
|
|
101
93
|
/**
|
|
102
94
|
* @since 1.0.0
|
|
103
95
|
*/
|
|
104
|
-
export * as
|
|
105
|
-
/**
|
|
106
|
-
* @since 1.0.0
|
|
107
|
-
*/
|
|
108
|
-
export * as ShardManager from "./ShardManager.js";
|
|
96
|
+
export * as Runners from "./Runners.js";
|
|
109
97
|
/**
|
|
110
98
|
* @since 1.0.0
|
|
111
99
|
*/
|
|
112
|
-
export * as
|
|
100
|
+
export * as ShardId from "./ShardId.js";
|
|
113
101
|
/**
|
|
114
102
|
* @since 1.0.0
|
|
115
103
|
*/
|
|
@@ -138,10 +126,6 @@ export * as Snowflake from "./Snowflake.js";
|
|
|
138
126
|
* @since 1.0.0
|
|
139
127
|
*/
|
|
140
128
|
export * as SocketRunner from "./SocketRunner.js";
|
|
141
|
-
/**
|
|
142
|
-
* @since 1.0.0
|
|
143
|
-
*/
|
|
144
|
-
export * as SocketShardManager from "./SocketShardManager.js";
|
|
145
129
|
/**
|
|
146
130
|
* @since 1.0.0
|
|
147
131
|
*/
|
|
@@ -149,9 +133,5 @@ export * as SqlMessageStorage from "./SqlMessageStorage.js";
|
|
|
149
133
|
/**
|
|
150
134
|
* @since 1.0.0
|
|
151
135
|
*/
|
|
152
|
-
export * as
|
|
153
|
-
/**
|
|
154
|
-
* @since 1.0.0
|
|
155
|
-
*/
|
|
156
|
-
export * as SynchronizedClock from "./SynchronizedClock.js";
|
|
136
|
+
export * as SqlRunnerStorage from "./SqlRunnerStorage.js";
|
|
157
137
|
//# sourceMappingURL=index.js.map
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["ClusterCron","ClusterError","ClusterMetrics","ClusterSchema","ClusterWorkflowEngine","DeliverAt","Entity","EntityAddress","EntityId","EntityProxy","EntityProxyServer","EntityType","Envelope","
|
|
1
|
+
{"version":3,"file":"index.js","names":["ClusterCron","ClusterError","ClusterMetrics","ClusterSchema","ClusterWorkflowEngine","DeliverAt","Entity","EntityAddress","EntityId","EntityProxy","EntityProxyServer","EntityType","Envelope","HttpRunner","MachineId","Message","MessageStorage","Reply","Runner","RunnerAddress","RunnerHealth","RunnerServer","RunnerStorage","Runners","ShardId","Sharding","ShardingConfig","ShardingRegistrationEvent","Singleton","SingletonAddress","Snowflake","SocketRunner","SqlMessageStorage","SqlRunnerStorage"],"sources":["../../src/index.ts"],"sourcesContent":[null],"mappings":"AAAA;;;AAGA,OAAO,KAAKA,WAAW,MAAM,kBAAkB;AAE/C;;;AAGA,OAAO,KAAKC,YAAY,MAAM,mBAAmB;AAEjD;;;AAGA,OAAO,KAAKC,cAAc,MAAM,qBAAqB;AAErD;;;AAGA,OAAO,KAAKC,aAAa,MAAM,oBAAoB;AAEnD;;;AAGA,OAAO,KAAKC,qBAAqB,MAAM,4BAA4B;AAEnE;;;AAGA,OAAO,KAAKC,SAAS,MAAM,gBAAgB;AAE3C;;;AAGA,OAAO,KAAKC,MAAM,MAAM,aAAa;AAErC;;;AAGA,OAAO,KAAKC,aAAa,MAAM,oBAAoB;AAEnD;;;AAGA,OAAO,KAAKC,QAAQ,MAAM,eAAe;AAEzC;;;AAGA,OAAO,KAAKC,WAAW,MAAM,kBAAkB;AAE/C;;;AAGA,OAAO,KAAKC,iBAAiB,MAAM,wBAAwB;AAE3D;;;AAGA,OAAO,KAAKC,UAAU,MAAM,iBAAiB;AAE7C;;;AAGA,OAAO,KAAKC,QAAQ,MAAM,eAAe;AAEzC;;;AAGA,OAAO,KAAKC,UAAU,MAAM,iBAAiB;AAE7C;;;AAGA,OAAO,KAAKC,SAAS,MAAM,gBAAgB;AAE3C;;;AAGA,OAAO,KAAKC,OAAO,MAAM,cAAc;AAEvC;;;AAGA,OAAO,KAAKC,cAAc,MAAM,qBAAqB;AAErD;;;AAGA,OAAO,KAAKC,KAAK,MAAM,YAAY;AAEnC;;;AAGA,OAAO,KAAKC,MAAM,MAAM,aAAa;AAErC;;;AAGA,OAAO,KAAKC,aAAa,MAAM,oBAAoB;AAEnD;;;AAGA,OAAO,KAAKC,YAAY,MAAM,mBAAmB;AAEjD;;;AAGA,OAAO,KAAKC,YAAY,MAAM,mBAAmB;AAEjD;;;AAGA,OAAO,KAAKC,aAAa,MAAM,oBAAoB;AAEnD;;;AAGA,OAAO,KAAKC,OAAO,MAAM,cAAc;AAEvC;;;AAGA,OAAO,KAAKC,OAAO,MAAM,cAAc;AAEvC;;;AAGA,OAAO,KAAKC,QAAQ,MAAM,eAAe;AAEzC;;;AAGA,OAAO,KAAKC,cAAc,MAAM,qBAAqB;AAErD;;;AAGA,OAAO,KAAKC,yBAAyB,MAAM,gCAAgC;AAE3E;;;AAGA,OAAO,KAAKC,SAAS,MAAM,gBAAgB;AAE3C;;;AAGA,OAAO,KAAKC,gBAAgB,MAAM,uBAAuB;AAEzD;;;AAGA,OAAO,KAAKC,SAAS,MAAM,gBAAgB;AAE3C;;;AAGA,OAAO,KAAKC,YAAY,MAAM,mBAAmB;AAEjD;;;AAGA,OAAO,KAAKC,iBAAiB,MAAM,wBAAwB;AAE3D;;;AAGA,OAAO,KAAKC,gBAAgB,MAAM,uBAAuB","ignoreList":[]}
|
|
@@ -43,8 +43,10 @@ export const make = /*#__PURE__*/Effect.fnUntraced(function* (entity, buildHandl
|
|
|
43
43
|
const context = yield* Effect.context();
|
|
44
44
|
const retryDriver = yield* Schedule.driver(options.defectRetryPolicy ? Schedule.andThen(options.defectRetryPolicy, defaultRetryPolicy) : defaultRetryPolicy);
|
|
45
45
|
const activeServers = new Map();
|
|
46
|
+
const serverCloseLatches = new Map();
|
|
47
|
+
const processedRequestIds = new Set();
|
|
46
48
|
const entities = yield* ResourceMap.make(Effect.fnUntraced(function* (address) {
|
|
47
|
-
if (
|
|
49
|
+
if (!options.sharding.hasShardId(address.shardId)) {
|
|
48
50
|
return yield* new EntityNotAssignedToRunner({
|
|
49
51
|
address
|
|
50
52
|
});
|
|
@@ -52,7 +54,11 @@ export const make = /*#__PURE__*/Effect.fnUntraced(function* (entity, buildHandl
|
|
|
52
54
|
const scope = yield* Effect.scope;
|
|
53
55
|
const endLatch = yield* Effect.makeLatch();
|
|
54
56
|
// on shutdown, reset the storage for the entity
|
|
55
|
-
yield* Scope.
|
|
57
|
+
yield* Scope.addFinalizerExit(scope, () => {
|
|
58
|
+
serverCloseLatches.get(address)?.unsafeOpen();
|
|
59
|
+
serverCloseLatches.delete(address);
|
|
60
|
+
return Effect.ignore(options.storage.resetAddress(address));
|
|
61
|
+
});
|
|
56
62
|
const activeRequests = new Map();
|
|
57
63
|
let defectRequestIds = [];
|
|
58
64
|
// the server is stored in a ref, so if there is a defect, we can
|
|
@@ -82,6 +88,18 @@ export const make = /*#__PURE__*/Effect.fnUntraced(function* (entity, buildHandl
|
|
|
82
88
|
// Also, if the request is uninterruptible, we ignore the
|
|
83
89
|
// interrupt.
|
|
84
90
|
if (storageEnabled && Context.get(request.rpc.annotations, Persisted) && Exit.isFailure(response.exit) && Exit.isInterrupted(response.exit) && (isShuttingDown || Context.get(request.rpc.annotations, Uninterruptible) || isInterruptIgnore(response.exit.cause))) {
|
|
91
|
+
if (!isShuttingDown) {
|
|
92
|
+
return server.write(0, {
|
|
93
|
+
...request.message.envelope,
|
|
94
|
+
id: RequestId(request.message.envelope.requestId),
|
|
95
|
+
tag: request.message.envelope.tag,
|
|
96
|
+
payload: new Request({
|
|
97
|
+
...request.message.envelope,
|
|
98
|
+
lastSentChunk: request.lastSentChunk
|
|
99
|
+
})
|
|
100
|
+
}).pipe(Effect.forkIn(scope));
|
|
101
|
+
}
|
|
102
|
+
activeRequests.delete(response.requestId);
|
|
85
103
|
return options.storage.unregisterReplyHandler(request.message.envelope.requestId);
|
|
86
104
|
}
|
|
87
105
|
return retryRespond(4, Effect.suspend(() => request.message.respond(new Reply.WithExit({
|
|
@@ -89,6 +107,7 @@ export const make = /*#__PURE__*/Effect.fnUntraced(function* (entity, buildHandl
|
|
|
89
107
|
id: snowflakeGen.unsafeNext(),
|
|
90
108
|
exit: response.exit
|
|
91
109
|
})))).pipe(Effect.flatMap(() => {
|
|
110
|
+
processedRequestIds.add(request.message.envelope.requestId);
|
|
92
111
|
activeRequests.delete(response.requestId);
|
|
93
112
|
// ensure that the reaper does not remove the entity as we haven't
|
|
94
113
|
// been "idle" yet
|
|
@@ -181,6 +200,7 @@ export const make = /*#__PURE__*/Effect.fnUntraced(function* (entity, buildHandl
|
|
|
181
200
|
// If the termination timeout is reached, let the server clean itself up
|
|
182
201
|
yield* Scope.addFinalizer(scope, Effect.withFiberRuntime(fiber => {
|
|
183
202
|
activeServers.delete(address.entityId);
|
|
203
|
+
serverCloseLatches.set(address, Effect.unsafeMakeLatch(false));
|
|
184
204
|
internalInterruptors.add(fiber.id());
|
|
185
205
|
return state.write(0, {
|
|
186
206
|
_tag: "Eof"
|
|
@@ -212,7 +232,7 @@ export const make = /*#__PURE__*/Effect.fnUntraced(function* (entity, buildHandl
|
|
|
212
232
|
// one sender for the same request. In this case, the other senders
|
|
213
233
|
// should resume from storage only.
|
|
214
234
|
let entry = server.activeRequests.get(message.envelope.requestId);
|
|
215
|
-
if (entry) {
|
|
235
|
+
if (entry || processedRequestIds.has(message.envelope.requestId)) {
|
|
216
236
|
return Effect.fail(new AlreadyProcessingMessage({
|
|
217
237
|
envelopeId: message.envelope.requestId,
|
|
218
238
|
address: message.envelope.address
|
|
@@ -268,16 +288,21 @@ export const make = /*#__PURE__*/Effect.fnUntraced(function* (entity, buildHandl
|
|
|
268
288
|
}), FiberRef.currentLogAnnotations, HashMap.empty());
|
|
269
289
|
}
|
|
270
290
|
const interruptShard = shardId => Effect.suspend(function loop() {
|
|
271
|
-
const
|
|
272
|
-
|
|
291
|
+
const toAwait = Arr.empty();
|
|
292
|
+
activeServers.forEach(state => {
|
|
273
293
|
if (shardId[Equal.symbol](state.address.shardId)) {
|
|
274
|
-
|
|
294
|
+
toAwait.push(entities.removeIgnore(state.address));
|
|
275
295
|
}
|
|
276
|
-
}
|
|
277
|
-
|
|
296
|
+
});
|
|
297
|
+
serverCloseLatches.forEach((latch, address) => {
|
|
298
|
+
if (shardId[Equal.symbol](address.shardId)) {
|
|
299
|
+
toAwait.push(latch.await);
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
if (toAwait.length === 0) {
|
|
278
303
|
return Effect.void;
|
|
279
304
|
}
|
|
280
|
-
return Effect.flatMap(Effect.
|
|
305
|
+
return Effect.flatMap(Effect.all(toAwait, {
|
|
281
306
|
concurrency: "unbounded",
|
|
282
307
|
discard: true
|
|
283
308
|
}), loop);
|
|
@@ -286,6 +311,9 @@ export const make = /*#__PURE__*/Effect.fnUntraced(function* (entity, buildHandl
|
|
|
286
311
|
return identity({
|
|
287
312
|
interruptShard,
|
|
288
313
|
isProcessingFor(message, options) {
|
|
314
|
+
if (options?.excludeReplies !== true && processedRequestIds.has(message.envelope.requestId)) {
|
|
315
|
+
return true;
|
|
316
|
+
}
|
|
289
317
|
const state = activeServers.get(message.envelope.address.entityId);
|
|
290
318
|
if (!state) return false;
|
|
291
319
|
const request = state.activeRequests.get(message.envelope.requestId);
|
|
@@ -296,6 +324,9 @@ export const make = /*#__PURE__*/Effect.fnUntraced(function* (entity, buildHandl
|
|
|
296
324
|
}
|
|
297
325
|
return true;
|
|
298
326
|
},
|
|
327
|
+
clearProcessed() {
|
|
328
|
+
processedRequestIds.clear();
|
|
329
|
+
},
|
|
299
330
|
sendLocal,
|
|
300
331
|
send: message => decodeMessage(message).pipe(Effect.matchEffect({
|
|
301
332
|
onFailure: cause => {
|