@opengeni/core 0.11.8 → 0.12.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/dist/index.d.ts +35 -9
- package/dist/index.js +233 -120
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
- package/src/dependencies.ts +2 -0
- package/src/domain/scheduled-tasks.ts +31 -1
- package/src/domain/sessions.ts +7 -0
- package/src/domain/slack-bot.ts +130 -0
- package/src/index.ts +1 -0
- package/src/sandbox/routing.ts +284 -243
package/src/sandbox/routing.ts
CHANGED
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
// real DB pointer + the live NATS control plane for the API-DIRECT Channel-A path
|
|
3
3
|
// (M7). Symmetric with apps/worker/src/sandbox-routing.ts (the turn path).
|
|
4
4
|
//
|
|
5
|
-
// A Channel-A op
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
// established group session is wrapped in a `RoutingSandboxSession` that re-reads
|
|
5
|
+
// A Channel-A op runs against one established home: either a lease-owned provider
|
|
6
|
+
// box or a Connected Machine home that intentionally has no cloud lease. With
|
|
7
|
+
// hot-swap, the op must land on the session's CURRENTLY-active sandbox. The
|
|
8
|
+
// established session is wrapped in a `RoutingSandboxSession` that re-reads
|
|
10
9
|
// (active_sandbox_id, active_epoch) and dispatches to the active backend.
|
|
11
10
|
//
|
|
12
11
|
// The DB-coupled glue (readActiveSandbox / getSandbox / the selfhosted ControlRpc
|
|
@@ -112,11 +111,10 @@ export function routingEnabled(settings: Settings): boolean {
|
|
|
112
111
|
}
|
|
113
112
|
|
|
114
113
|
/**
|
|
115
|
-
* Wrap an established
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
* unchanged; a selfhosted active pointer routes the op to the machine.
|
|
114
|
+
* Wrap an established home session in a `RoutingSandboxSession` so a Channel-A
|
|
115
|
+
* op routes to the session's currently-active sandbox. Provider homes supply a
|
|
116
|
+
* lease; machine homes supply a pinned selfhosted identity and no lease. Returns
|
|
117
|
+
* the established handle with its `session` replaced by the stable proxy.
|
|
120
118
|
*/
|
|
121
119
|
export function wrapChannelABoxWithRouting(
|
|
122
120
|
services: ChannelARoutingServices,
|
|
@@ -124,12 +122,19 @@ export function wrapChannelABoxWithRouting(
|
|
|
124
122
|
accountId: string;
|
|
125
123
|
workspaceId: string;
|
|
126
124
|
sessionId: string;
|
|
127
|
-
homeLease
|
|
125
|
+
homeLease?: {
|
|
128
126
|
sandboxGroupId: string;
|
|
129
127
|
leaseEpoch: number;
|
|
130
128
|
instanceId: string;
|
|
131
129
|
backend: string;
|
|
132
130
|
};
|
|
131
|
+
/** A machine-home Channel-A request has no cloud/home lease. Its already
|
|
132
|
+
* established SelfhostedSession is pinned to the durable active pointer so
|
|
133
|
+
* the first command uses the exact machine instance and epoch. */
|
|
134
|
+
pinnedSelfhosted?: {
|
|
135
|
+
sandboxId: string;
|
|
136
|
+
epoch: number;
|
|
137
|
+
};
|
|
133
138
|
directRequest: {
|
|
134
139
|
requestId: string;
|
|
135
140
|
holderId: string;
|
|
@@ -138,199 +143,212 @@ export function wrapChannelABoxWithRouting(
|
|
|
138
143
|
established: EstablishedSandboxSession,
|
|
139
144
|
): EstablishedSandboxSession {
|
|
140
145
|
const { db, settings, bus } = services;
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
146
|
+
const homeLease = ids.homeLease;
|
|
147
|
+
const beforeMutation = homeLease
|
|
148
|
+
? async ({
|
|
149
|
+
op,
|
|
150
|
+
backend,
|
|
151
|
+
}: {
|
|
152
|
+
op: string;
|
|
153
|
+
backend: ResolvedActiveBackend;
|
|
154
|
+
}): Promise<SandboxWorkspaceMutationAdmission | null> => {
|
|
155
|
+
// Connected Machines and other non-persistable targets intentionally do
|
|
156
|
+
// not dirty or advance the cloud-home archive generation.
|
|
157
|
+
if (
|
|
158
|
+
backend.sandboxId !== null ||
|
|
159
|
+
backend.leaseEpoch === undefined ||
|
|
160
|
+
backend.providerInstanceId === undefined
|
|
161
|
+
) {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
if (backend.activeEpoch === undefined) {
|
|
165
|
+
throw new Error("API-direct workspace mutation resolved without an active route epoch");
|
|
166
|
+
}
|
|
167
|
+
return await advanceWorkspaceGenerationForDirectRequest(db, {
|
|
168
|
+
accountId: ids.accountId,
|
|
169
|
+
workspaceId: ids.workspaceId,
|
|
170
|
+
sessionId: ids.sessionId,
|
|
171
|
+
requestId: ids.directRequest.requestId,
|
|
172
|
+
holderId: ids.directRequest.holderId,
|
|
173
|
+
sandboxGroupId: homeLease.sandboxGroupId,
|
|
174
|
+
expectedEpoch: backend.leaseEpoch,
|
|
175
|
+
expectedInstanceId: backend.providerInstanceId,
|
|
176
|
+
routeTargetId: backend.sandboxId,
|
|
177
|
+
routeEpoch: backend.activeEpoch,
|
|
178
|
+
operation: op,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
: undefined;
|
|
182
|
+
const afterMutation = homeLease
|
|
183
|
+
? async ({
|
|
184
|
+
op,
|
|
185
|
+
backend,
|
|
186
|
+
admission,
|
|
187
|
+
outcome,
|
|
188
|
+
retainedProcess,
|
|
189
|
+
}: {
|
|
190
|
+
op: string;
|
|
191
|
+
backend: ResolvedActiveBackend;
|
|
192
|
+
admission: unknown;
|
|
193
|
+
outcome: "resolved" | "rejected";
|
|
194
|
+
result?: unknown;
|
|
195
|
+
retainedProcess?: RoutingRetainedProcess;
|
|
196
|
+
}): Promise<void> => {
|
|
197
|
+
if (admission === null) return;
|
|
198
|
+
if (
|
|
199
|
+
!admission ||
|
|
200
|
+
typeof admission !== "object" ||
|
|
201
|
+
typeof (admission as Partial<SandboxWorkspaceMutationAdmission>).id !== "string" ||
|
|
202
|
+
typeof (admission as Partial<SandboxWorkspaceMutationAdmission>).workspaceGeneration !==
|
|
203
|
+
"number" ||
|
|
204
|
+
backend.leaseEpoch === undefined ||
|
|
205
|
+
backend.providerInstanceId === undefined ||
|
|
206
|
+
backend.activeEpoch === undefined
|
|
207
|
+
) {
|
|
208
|
+
throw new Error("API-direct workspace mutation settlement lacked its exact admission");
|
|
209
|
+
}
|
|
210
|
+
const exactAdmission = admission as SandboxWorkspaceMutationAdmission;
|
|
211
|
+
if (outcome === "resolved" && retainedProcess) {
|
|
212
|
+
await retainWorkspaceMutationProcess(db, {
|
|
213
|
+
accountId: ids.accountId,
|
|
214
|
+
workspaceId: ids.workspaceId,
|
|
215
|
+
sessionId: ids.sessionId,
|
|
216
|
+
processId: retainedProcess.id,
|
|
217
|
+
providerSessionId: retainedProcess.providerSessionId,
|
|
218
|
+
admissionId: exactAdmission.id,
|
|
219
|
+
admittedWorkspaceGeneration: exactAdmission.workspaceGeneration,
|
|
220
|
+
operation: op,
|
|
221
|
+
owner: {
|
|
222
|
+
kind: "direct",
|
|
223
|
+
requestId: ids.directRequest.requestId,
|
|
224
|
+
holderId: ids.directRequest.holderId,
|
|
225
|
+
sandboxGroupId: homeLease.sandboxGroupId,
|
|
226
|
+
expectedEpoch: backend.leaseEpoch,
|
|
227
|
+
expectedInstanceId: backend.providerInstanceId,
|
|
228
|
+
routeTargetId: exactAdmission.routeTargetId,
|
|
229
|
+
routeEpoch: exactAdmission.routeEpoch,
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
await verifyDirectWorkspaceMutationSettlement(db, {
|
|
235
|
+
accountId: ids.accountId,
|
|
236
|
+
workspaceId: ids.workspaceId,
|
|
237
|
+
sessionId: ids.sessionId,
|
|
214
238
|
requestId: ids.directRequest.requestId,
|
|
215
239
|
holderId: ids.directRequest.holderId,
|
|
216
|
-
sandboxGroupId:
|
|
240
|
+
sandboxGroupId: homeLease.sandboxGroupId,
|
|
217
241
|
expectedEpoch: backend.leaseEpoch,
|
|
218
242
|
expectedInstanceId: backend.providerInstanceId,
|
|
219
243
|
routeTargetId: exactAdmission.routeTargetId,
|
|
220
244
|
routeEpoch: exactAdmission.routeEpoch,
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
outcome: proof.outcome,
|
|
329
|
-
exitCode: proof.exitCode,
|
|
330
|
-
reason: proof.reason,
|
|
331
|
-
idleGraceMs: settings.sandboxIdleGraceMs,
|
|
332
|
-
});
|
|
333
|
-
};
|
|
245
|
+
admission: exactAdmission,
|
|
246
|
+
operation: op,
|
|
247
|
+
outcome,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
: undefined;
|
|
251
|
+
const beforeProcessMutation = homeLease
|
|
252
|
+
? async ({
|
|
253
|
+
op,
|
|
254
|
+
process,
|
|
255
|
+
}: {
|
|
256
|
+
op: string;
|
|
257
|
+
backend: ResolvedActiveBackend;
|
|
258
|
+
process: RoutingRetainedProcess;
|
|
259
|
+
}): Promise<SandboxWorkspaceMutationAdmission> =>
|
|
260
|
+
await advanceWorkspaceGenerationForRetainedProcess(db, {
|
|
261
|
+
accountId: ids.accountId,
|
|
262
|
+
workspaceId: ids.workspaceId,
|
|
263
|
+
sessionId: ids.sessionId,
|
|
264
|
+
processId: process.id,
|
|
265
|
+
operation: op,
|
|
266
|
+
})
|
|
267
|
+
: undefined;
|
|
268
|
+
const afterProcessMutation = homeLease
|
|
269
|
+
? async ({
|
|
270
|
+
op,
|
|
271
|
+
process,
|
|
272
|
+
admission,
|
|
273
|
+
outcome,
|
|
274
|
+
}: {
|
|
275
|
+
op: string;
|
|
276
|
+
backend: ResolvedActiveBackend;
|
|
277
|
+
process: RoutingRetainedProcess;
|
|
278
|
+
admission: unknown;
|
|
279
|
+
outcome: "resolved" | "rejected";
|
|
280
|
+
result?: unknown;
|
|
281
|
+
}): Promise<void> => {
|
|
282
|
+
if (
|
|
283
|
+
!admission ||
|
|
284
|
+
typeof admission !== "object" ||
|
|
285
|
+
typeof (admission as Partial<SandboxWorkspaceMutationAdmission>).id !== "string" ||
|
|
286
|
+
typeof (admission as Partial<SandboxWorkspaceMutationAdmission>).workspaceGeneration !==
|
|
287
|
+
"number"
|
|
288
|
+
) {
|
|
289
|
+
throw new Error("API retained-process mutation settlement lacked its exact admission");
|
|
290
|
+
}
|
|
291
|
+
await verifyRetainedProcessMutationSettlement(db, {
|
|
292
|
+
accountId: ids.accountId,
|
|
293
|
+
workspaceId: ids.workspaceId,
|
|
294
|
+
sessionId: ids.sessionId,
|
|
295
|
+
processId: process.id,
|
|
296
|
+
admission: admission as SandboxWorkspaceMutationAdmission,
|
|
297
|
+
operation: op,
|
|
298
|
+
outcome,
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
: undefined;
|
|
302
|
+
const settleProcess = homeLease
|
|
303
|
+
? async ({
|
|
304
|
+
backend,
|
|
305
|
+
process,
|
|
306
|
+
proof,
|
|
307
|
+
}: {
|
|
308
|
+
backend: ResolvedActiveBackend;
|
|
309
|
+
process: RoutingRetainedProcess;
|
|
310
|
+
proof: RoutingRetainedProcessTerminalProof;
|
|
311
|
+
}): Promise<void> => {
|
|
312
|
+
if (
|
|
313
|
+
backend.sandboxId !== null ||
|
|
314
|
+
backend.leaseEpoch === undefined ||
|
|
315
|
+
backend.providerInstanceId === undefined ||
|
|
316
|
+
backend.activeEpoch === undefined
|
|
317
|
+
) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
const durable = await getRetainedProcess(db, {
|
|
321
|
+
workspaceId: ids.workspaceId,
|
|
322
|
+
sessionId: ids.sessionId,
|
|
323
|
+
processId: process.id,
|
|
324
|
+
});
|
|
325
|
+
if (
|
|
326
|
+
!durable ||
|
|
327
|
+
durable.providerSessionId !== process.providerSessionId ||
|
|
328
|
+
durable.providerBackend !== backend.kind ||
|
|
329
|
+
durable.providerInstanceId !== backend.providerInstanceId ||
|
|
330
|
+
durable.leaseEpoch !== backend.leaseEpoch ||
|
|
331
|
+
durable.routeKind !== (backend.sandboxId === null ? "home" : "active") ||
|
|
332
|
+
durable.routeTargetId !== backend.sandboxId ||
|
|
333
|
+
durable.routeEpoch !== backend.activeEpoch
|
|
334
|
+
) {
|
|
335
|
+
throw new Error(
|
|
336
|
+
"API retained-process settlement lost its exact durable backend identity",
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
await settleRetainedProcess(db, {
|
|
340
|
+
accountId: ids.accountId,
|
|
341
|
+
workspaceId: ids.workspaceId,
|
|
342
|
+
sessionId: ids.sessionId,
|
|
343
|
+
processId: process.id,
|
|
344
|
+
expected: retainedProcessSettlementIdentity(durable),
|
|
345
|
+
outcome: proof.outcome,
|
|
346
|
+
exitCode: proof.exitCode,
|
|
347
|
+
reason: proof.reason,
|
|
348
|
+
idleGraceMs: settings.sandboxIdleGraceMs,
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
: undefined;
|
|
334
352
|
const resolver = makeActiveBackendResolver({
|
|
335
353
|
workspaceId: ids.workspaceId,
|
|
336
354
|
defaultBackend: established.session as RoutableBackendSession,
|
|
@@ -348,13 +366,28 @@ export function wrapChannelABoxWithRouting(
|
|
|
348
366
|
},
|
|
349
367
|
controlRpcFactory: controlRpcFactory(bus),
|
|
350
368
|
relay: relayConfigFromSettings(settings),
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
369
|
+
selfhostedTimeoutMs: settings.sandboxSelfhostedControlTimeoutMs,
|
|
370
|
+
selfhostedExecTimeoutMs: settings.sandboxSelfhostedExecTimeoutMs,
|
|
371
|
+
...(ids.pinnedSelfhosted
|
|
372
|
+
? {
|
|
373
|
+
pinnedSelfhosted: {
|
|
374
|
+
sandboxId: ids.pinnedSelfhosted.sandboxId,
|
|
375
|
+
epoch: ids.pinnedSelfhosted.epoch,
|
|
376
|
+
session: established.session as RoutableBackendSession,
|
|
377
|
+
},
|
|
378
|
+
}
|
|
379
|
+
: {}),
|
|
380
|
+
...(homeLease
|
|
381
|
+
? {
|
|
382
|
+
resolveDefaultBackend: async () => ({
|
|
383
|
+
session: established.session as RoutableBackendSession,
|
|
384
|
+
sandboxId: null,
|
|
385
|
+
kind: established.backendId,
|
|
386
|
+
leaseEpoch: homeLease.leaseEpoch,
|
|
387
|
+
providerInstanceId: homeLease.instanceId,
|
|
388
|
+
}),
|
|
389
|
+
}
|
|
390
|
+
: {}),
|
|
358
391
|
});
|
|
359
392
|
|
|
360
393
|
const proxy = new RoutingSandboxSession({
|
|
@@ -362,8 +395,12 @@ export function wrapChannelABoxWithRouting(
|
|
|
362
395
|
session: established.session as RoutableBackendSession,
|
|
363
396
|
sandboxId: null,
|
|
364
397
|
kind: established.backendId,
|
|
365
|
-
|
|
366
|
-
|
|
398
|
+
...(homeLease
|
|
399
|
+
? {
|
|
400
|
+
leaseEpoch: homeLease.leaseEpoch,
|
|
401
|
+
providerInstanceId: homeLease.instanceId,
|
|
402
|
+
}
|
|
403
|
+
: {}),
|
|
367
404
|
},
|
|
368
405
|
readPointer: async () => {
|
|
369
406
|
if (!routingEnabled(settings)) {
|
|
@@ -373,43 +410,47 @@ export function wrapChannelABoxWithRouting(
|
|
|
373
410
|
return pointer ?? { activeSandboxId: null, activeEpoch: 0 };
|
|
374
411
|
},
|
|
375
412
|
resolveActiveBackend: resolver,
|
|
376
|
-
beforeMutation,
|
|
377
|
-
afterMutation,
|
|
378
|
-
beforeProcessMutation,
|
|
379
|
-
afterProcessMutation,
|
|
380
|
-
settleProcess,
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
413
|
+
...(beforeMutation ? { beforeMutation } : {}),
|
|
414
|
+
...(afterMutation ? { afterMutation } : {}),
|
|
415
|
+
...(beforeProcessMutation ? { beforeProcessMutation } : {}),
|
|
416
|
+
...(afterProcessMutation ? { afterProcessMutation } : {}),
|
|
417
|
+
...(settleProcess ? { settleProcess } : {}),
|
|
418
|
+
...(homeLease
|
|
419
|
+
? {
|
|
420
|
+
onDefaultBackendError: async ({ error }: { error: unknown }) => {
|
|
421
|
+
if (!isProviderSandboxGoneDuringRoutedOperation(homeLease.backend, error)) return null;
|
|
422
|
+
const marked = await markWarmLeaseInstanceLost(db, {
|
|
423
|
+
accountId: ids.accountId,
|
|
424
|
+
workspaceId: ids.workspaceId,
|
|
425
|
+
sandboxGroupId: homeLease.sandboxGroupId,
|
|
426
|
+
expectedEpoch: homeLease.leaseEpoch,
|
|
427
|
+
expectedInstanceId: homeLease.instanceId,
|
|
428
|
+
diagnostic: "provider_not_found_during_routed_operation",
|
|
429
|
+
});
|
|
430
|
+
if (marked.status === "marked" && bus) {
|
|
431
|
+
await appendAndPublishEvents(db, bus, ids.workspaceId, ids.sessionId, [
|
|
432
|
+
{
|
|
433
|
+
type: "sandbox.box.lost",
|
|
434
|
+
payload: { sandboxId: homeLease.instanceId },
|
|
435
|
+
},
|
|
436
|
+
]).catch(() => undefined);
|
|
437
|
+
}
|
|
438
|
+
const lease = marked.lease;
|
|
439
|
+
const restore = lease?.recovery.restore.status;
|
|
440
|
+
return {
|
|
441
|
+
leaseEpoch: lease?.leaseEpoch ?? homeLease.leaseEpoch,
|
|
442
|
+
recovery:
|
|
443
|
+
marked.status === "stale"
|
|
444
|
+
? ("superseded" as const)
|
|
445
|
+
: restore === "pending"
|
|
446
|
+
? ("pending" as const)
|
|
447
|
+
: restore === "degraded"
|
|
448
|
+
? ("degraded" as const)
|
|
449
|
+
: ("unrecoverable" as const),
|
|
450
|
+
};
|
|
396
451
|
},
|
|
397
|
-
|
|
398
|
-
}
|
|
399
|
-
const lease = marked.lease;
|
|
400
|
-
const restore = lease?.recovery.restore.status;
|
|
401
|
-
return {
|
|
402
|
-
leaseEpoch: lease?.leaseEpoch ?? ids.homeLease.leaseEpoch,
|
|
403
|
-
recovery:
|
|
404
|
-
marked.status === "stale"
|
|
405
|
-
? ("superseded" as const)
|
|
406
|
-
: restore === "pending"
|
|
407
|
-
? ("pending" as const)
|
|
408
|
-
: restore === "degraded"
|
|
409
|
-
? ("degraded" as const)
|
|
410
|
-
: ("unrecoverable" as const),
|
|
411
|
-
};
|
|
412
|
-
},
|
|
452
|
+
}
|
|
453
|
+
: {}),
|
|
413
454
|
});
|
|
414
455
|
|
|
415
456
|
return { ...established, session: proxy };
|