@typeonce/effect-machine 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +89 -13
- package/dist/Machine.d.ts +396 -127
- package/dist/Machine.d.ts.map +1 -1
- package/dist/Machine.js +21 -19
- package/dist/Machine.js.map +1 -1
- package/dist/internal/machine/atom.d.ts +1 -0
- package/dist/internal/machine/atom.d.ts.map +1 -1
- package/dist/internal/machine/atom.js +23 -0
- package/dist/internal/machine/atom.js.map +1 -1
- package/dist/internal/machine/cluster.js +2 -2
- package/dist/internal/machine/cluster.js.map +1 -1
- package/dist/internal/machine/commandRuntime.d.ts.map +1 -1
- package/dist/internal/machine/commandRuntime.js +2 -5
- package/dist/internal/machine/commandRuntime.js.map +1 -1
- package/dist/internal/machine/configuration.d.ts +12 -7
- package/dist/internal/machine/configuration.d.ts.map +1 -1
- package/dist/internal/machine/configuration.js +9 -5
- package/dist/internal/machine/configuration.js.map +1 -1
- package/dist/internal/machine/executionPlan.d.ts +4 -3
- package/dist/internal/machine/executionPlan.d.ts.map +1 -1
- package/dist/internal/machine/executionPlan.js +68 -43
- package/dist/internal/machine/executionPlan.js.map +1 -1
- package/dist/internal/machine/initialization.d.ts +5 -0
- package/dist/internal/machine/initialization.d.ts.map +1 -0
- package/dist/internal/machine/initialization.js +61 -0
- package/dist/internal/machine/initialization.js.map +1 -0
- package/dist/internal/machine/inspectionRuntime.d.ts +25 -0
- package/dist/internal/machine/inspectionRuntime.d.ts.map +1 -0
- package/dist/internal/machine/inspectionRuntime.js +79 -0
- package/dist/internal/machine/inspectionRuntime.js.map +1 -0
- package/dist/internal/machine/invocation.d.ts +2 -1
- package/dist/internal/machine/invocation.d.ts.map +1 -1
- package/dist/internal/machine/invocation.js +18 -11
- package/dist/internal/machine/invocation.js.map +1 -1
- package/dist/internal/machine/machine.d.ts +1 -2
- package/dist/internal/machine/machine.d.ts.map +1 -1
- package/dist/internal/machine/machine.js +21 -6
- package/dist/internal/machine/machine.js.map +1 -1
- package/dist/internal/machine/planner.d.ts +17 -2
- package/dist/internal/machine/planner.d.ts.map +1 -1
- package/dist/internal/machine/planner.js +137 -64
- package/dist/internal/machine/planner.js.map +1 -1
- package/dist/internal/machine/process.d.ts.map +1 -1
- package/dist/internal/machine/process.js +7 -5
- package/dist/internal/machine/process.js.map +1 -1
- package/dist/internal/machine/runtime.d.ts +29 -5
- package/dist/internal/machine/runtime.d.ts.map +1 -1
- package/dist/internal/machine/runtime.js +440 -64
- package/dist/internal/machine/runtime.js.map +1 -1
- package/dist/internal/machine/symbols.d.ts +2 -0
- package/dist/internal/machine/symbols.d.ts.map +1 -1
- package/dist/internal/machine/symbols.js +2 -0
- package/dist/internal/machine/symbols.js.map +1 -1
- package/dist/internal/machine/topology.d.ts +13 -0
- package/dist/internal/machine/topology.d.ts.map +1 -1
- package/dist/internal/machine/topology.js +9 -0
- package/dist/internal/machine/topology.js.map +1 -1
- package/dist/internal/testing/machine/finiteModel.d.ts.map +1 -1
- package/dist/internal/testing/machine/finiteModel.js +3 -3
- package/dist/internal/testing/machine/finiteModel.js.map +1 -1
- package/dist/unstable/reactivity/AtomMachine.d.ts +9 -0
- package/dist/unstable/reactivity/AtomMachine.d.ts.map +1 -1
- package/dist/unstable/reactivity/AtomMachine.js +9 -0
- package/dist/unstable/reactivity/AtomMachine.js.map +1 -1
- package/docs/agent-guide.md +130 -20
- package/package.json +5 -5
- package/src/Machine.ts +548 -217
- package/src/internal/machine/atom.ts +26 -0
- package/src/internal/machine/cluster.ts +2 -2
- package/src/internal/machine/commandRuntime.ts +2 -7
- package/src/internal/machine/configuration.ts +38 -13
- package/src/internal/machine/executionPlan.ts +85 -52
- package/src/internal/machine/initialization.ts +73 -0
- package/src/internal/machine/inspectionRuntime.ts +102 -0
- package/src/internal/machine/invocation.ts +38 -13
- package/src/internal/machine/machine.ts +31 -6
- package/src/internal/machine/planner.ts +166 -66
- package/src/internal/machine/process.ts +7 -5
- package/src/internal/machine/runtime.ts +663 -91
- package/src/internal/machine/symbols.ts +3 -0
- package/src/internal/machine/topology.ts +27 -0
- package/src/internal/testing/machine/finiteModel.ts +8 -7
- package/src/unstable/reactivity/AtomMachine.ts +12 -0
|
@@ -17,6 +17,7 @@ import * as Scope from "effect/Scope";
|
|
|
17
17
|
import * as Stream from "effect/Stream";
|
|
18
18
|
import * as SynchronizedRef from "effect/SynchronizedRef";
|
|
19
19
|
import { ChildAlreadyExistsError, StoppedError } from "./errors.js";
|
|
20
|
+
import * as InspectionRuntime from "./inspectionRuntime.js";
|
|
20
21
|
/** @internal */
|
|
21
22
|
export const activeSnapshotObserver = Symbol.for("effect/Machine/activeSnapshotObserver");
|
|
22
23
|
/** @internal */
|
|
@@ -30,17 +31,22 @@ export const isAcknowledgedMessage = (message) => typeof message === "object" &&
|
|
|
30
31
|
export const messageEvent = (message) => isAcknowledgedMessage(message) ? message.event : message;
|
|
31
32
|
const succeedAcknowledgedMessage = (message, delivery) => {
|
|
32
33
|
if (message !== undefined && isAcknowledgedMessage(message)) {
|
|
33
|
-
|
|
34
|
+
if (message.deferred !== undefined) {
|
|
35
|
+
Deferred.doneUnsafe(message.deferred, Effect.succeed(delivery));
|
|
36
|
+
}
|
|
37
|
+
message.inspection?.complete(delivery);
|
|
34
38
|
}
|
|
35
39
|
};
|
|
36
40
|
const failAcknowledgedMessage = (message, cause) => {
|
|
37
41
|
if (message !== undefined && isAcknowledgedMessage(message)) {
|
|
38
|
-
|
|
42
|
+
if (message.deferred !== undefined)
|
|
43
|
+
Deferred.doneUnsafe(message.deferred, Effect.failCause(cause));
|
|
39
44
|
}
|
|
40
45
|
};
|
|
41
46
|
const stopAcknowledgedMessage = (message) => {
|
|
42
47
|
if (message !== undefined && isAcknowledgedMessage(message)) {
|
|
43
|
-
|
|
48
|
+
if (message.deferred !== undefined)
|
|
49
|
+
Deferred.doneUnsafe(message.deferred, Effect.fail(new StoppedError()));
|
|
44
50
|
}
|
|
45
51
|
};
|
|
46
52
|
const offerChildObservation = (observer, value) => {
|
|
@@ -112,7 +118,10 @@ const registerChild = (registry, key, token, ref, descriptor) => {
|
|
|
112
118
|
publishRegistryChange(registry);
|
|
113
119
|
return true;
|
|
114
120
|
};
|
|
115
|
-
const
|
|
121
|
+
const isMachineTarget = (value) => typeof value === "object" && value !== null && "send" in value && typeof value.send === "function";
|
|
122
|
+
const sendMachineTarget = (target, event, source, causedBy) => "inspectionSubject" in target && "sendInspected" in target && typeof target.sendInspected === "function"
|
|
123
|
+
? target.sendInspected(event, source, causedBy)
|
|
124
|
+
: target.send(event);
|
|
116
125
|
const executionIsChildless = (execution) => execution?._tag === "Childless" || execution?.childless === true;
|
|
117
126
|
const offerCompactMailbox = (mailbox, event) => {
|
|
118
127
|
const items = mailbox.items ?? [];
|
|
@@ -205,6 +214,63 @@ const makeProcessRuntime = Effect.sync(() => {
|
|
|
205
214
|
nextSessionId: Effect.sync(() => `machine:${sessionIdCounter++}`)
|
|
206
215
|
};
|
|
207
216
|
});
|
|
217
|
+
const inspectionSubject = (logic, id, sessionId) => ({
|
|
218
|
+
id,
|
|
219
|
+
sessionId,
|
|
220
|
+
kind: logic.inspection?.kind ?? "Logic"
|
|
221
|
+
});
|
|
222
|
+
const messageCausation = (message, initializing) => initializing
|
|
223
|
+
? { _tag: "Initialization" }
|
|
224
|
+
: message !== undefined && isAcknowledgedMessage(message) && message.inspection !== undefined
|
|
225
|
+
? { _tag: "Macrostep", macrostepId: message.inspection.macrostepId }
|
|
226
|
+
: undefined;
|
|
227
|
+
const makeInspectedMessage = (inspection, subject, event, source, causedBy, deferred) => {
|
|
228
|
+
const deliveryId = inspection.nextDeliveryId();
|
|
229
|
+
const macrostepId = inspection.nextMacrostepId();
|
|
230
|
+
const inspected = {
|
|
231
|
+
deliveryId,
|
|
232
|
+
macrostepId,
|
|
233
|
+
source,
|
|
234
|
+
event,
|
|
235
|
+
causedBy,
|
|
236
|
+
complete: (delivery) => {
|
|
237
|
+
const microsteps = InspectionRuntime.microsteps(delivery.plan);
|
|
238
|
+
inspection.publishUnsafe({
|
|
239
|
+
_tag: "EventProcessed",
|
|
240
|
+
subject,
|
|
241
|
+
macrostepId,
|
|
242
|
+
deliveryId,
|
|
243
|
+
source,
|
|
244
|
+
event,
|
|
245
|
+
before: { status: "active", state: delivery.before },
|
|
246
|
+
after: { status: "active", state: delivery.after },
|
|
247
|
+
handled: microsteps.some((microstep) => microstep.transitions.length > 0),
|
|
248
|
+
configurationChanged: microsteps.some((microstep) => microstep.changed),
|
|
249
|
+
microsteps
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
return {
|
|
254
|
+
[AcknowledgedMessageTypeId]: true,
|
|
255
|
+
event,
|
|
256
|
+
...(deferred === undefined ? undefined : { deferred }),
|
|
257
|
+
inspection: inspected
|
|
258
|
+
};
|
|
259
|
+
};
|
|
260
|
+
const publishInspectedSent = (inspection, subject, message) => {
|
|
261
|
+
if (!isAcknowledgedMessage(message) || message.inspection === undefined)
|
|
262
|
+
return;
|
|
263
|
+
const delivery = message.inspection;
|
|
264
|
+
inspection.publishUnsafe({
|
|
265
|
+
_tag: "EventSent",
|
|
266
|
+
subject,
|
|
267
|
+
deliveryId: delivery.deliveryId,
|
|
268
|
+
source: delivery.source,
|
|
269
|
+
target: InspectionRuntime.endpoint(subject),
|
|
270
|
+
event: delivery.event,
|
|
271
|
+
causedBy: delivery.causedBy
|
|
272
|
+
});
|
|
273
|
+
};
|
|
208
274
|
class OwnedChildRuntimeImpl {
|
|
209
275
|
registry;
|
|
210
276
|
self;
|
|
@@ -252,13 +318,14 @@ class OwnedChildRuntimeImpl {
|
|
|
252
318
|
});
|
|
253
319
|
const parent = {
|
|
254
320
|
...this.self,
|
|
255
|
-
send: (event) => options.sendParent(isCurrent, event)
|
|
321
|
+
send: (event) => options.sendParent(isCurrent, event),
|
|
322
|
+
sendInspected: (event, source, causedBy) => isCurrent() ? sendMachineTarget(this.self, event, source, causedBy) : Effect.void
|
|
256
323
|
};
|
|
257
324
|
const startOptions = {
|
|
258
325
|
detached: true,
|
|
259
326
|
id: options.id,
|
|
260
327
|
sendParent: (event) => options.sendParent(isCurrent, event),
|
|
261
|
-
onOutcome: (outcome) => options.onOutcome(isCurrent, outcome),
|
|
328
|
+
onOutcome: (outcome) => options.onOutcome(isCurrent, outcome, startedChild?.sessionId),
|
|
262
329
|
...(options.onSnapshot === undefined
|
|
263
330
|
? undefined
|
|
264
331
|
: { onSnapshot: (snapshot) => options.onSnapshot(isCurrent, snapshot) }),
|
|
@@ -269,7 +336,19 @@ class OwnedChildRuntimeImpl {
|
|
|
269
336
|
onStopSync: () => unregisterChild(this.registry, options.id, token),
|
|
270
337
|
skipStoppedOutcome: true,
|
|
271
338
|
parent,
|
|
272
|
-
runtime: this.runtime
|
|
339
|
+
runtime: this.runtime,
|
|
340
|
+
origin: { _tag: "Invoke", ownerPath: options.path, invokeId: options.duplicateId },
|
|
341
|
+
...(options.activityKind === undefined || this.runtime.inspection === undefined ||
|
|
342
|
+
this.self.inspectionSubject === undefined
|
|
343
|
+
? undefined
|
|
344
|
+
: {
|
|
345
|
+
activity: {
|
|
346
|
+
id: options.duplicateId,
|
|
347
|
+
owner: this.self.inspectionSubject,
|
|
348
|
+
ownerPath: options.path,
|
|
349
|
+
kind: options.activityKind
|
|
350
|
+
}
|
|
351
|
+
})
|
|
273
352
|
};
|
|
274
353
|
const execution = logic.execution;
|
|
275
354
|
const synchronous = this.services !== undefined && options.onSnapshot === undefined &&
|
|
@@ -320,6 +399,8 @@ class OwnedChildRuntimeImpl {
|
|
|
320
399
|
}
|
|
321
400
|
const noChildChanges = Stream.succeed(Option.none()).pipe(Stream.concat(Stream.never));
|
|
322
401
|
const noParentSend = (_event) => Effect.void;
|
|
402
|
+
const noInspectInitial = (_paths, _microsteps) => { };
|
|
403
|
+
const noCausation = () => undefined;
|
|
323
404
|
const EmissionsClosed = Symbol("effect/Machine/EmissionsClosed");
|
|
324
405
|
const makeEmissionRuntime = () => {
|
|
325
406
|
let emissions;
|
|
@@ -450,7 +531,7 @@ const makeChildRuntimeSync = (self, runtime, services) => {
|
|
|
450
531
|
})), Effect.as(takeChildObservations(observer)));
|
|
451
532
|
}))));
|
|
452
533
|
};
|
|
453
|
-
const sendTo = (child, event) => {
|
|
534
|
+
const sendTo = (child, event, source, causedBy) => {
|
|
454
535
|
const id = typeof child === "string" ? child : child.id;
|
|
455
536
|
return Effect.suspend(() => {
|
|
456
537
|
if (registry.closed) {
|
|
@@ -458,7 +539,7 @@ const makeChildRuntimeSync = (self, runtime, services) => {
|
|
|
458
539
|
}
|
|
459
540
|
const entry = registry.children.get(id);
|
|
460
541
|
return entry !== undefined && matchesChild(entry, child)
|
|
461
|
-
? entry.ref
|
|
542
|
+
? sendMachineTarget(entry.ref, event, source, causedBy)
|
|
462
543
|
: Effect.void;
|
|
463
544
|
});
|
|
464
545
|
};
|
|
@@ -502,7 +583,8 @@ const makeChildRuntimeSync = (self, runtime, services) => {
|
|
|
502
583
|
}).pipe(Effect.andThen(register(key, token, child, spawnOptions?.descriptor)), Effect.flatMap((registered) => registered ? Effect.void : requestChildStop)),
|
|
503
584
|
onStop: unregister(key, token),
|
|
504
585
|
parent: self,
|
|
505
|
-
runtime
|
|
586
|
+
runtime,
|
|
587
|
+
origin: { _tag: "Spawn", address: spawnOptions?.id }
|
|
506
588
|
}).pipe(Effect.onExit((exit) => Exit.isFailure(exit)
|
|
507
589
|
? unregister(key, token).pipe(Effect.andThen(startedChild === undefined ? Effect.void : startedChild.stop))
|
|
508
590
|
: Effect.void), Scope.provide(registry.scope));
|
|
@@ -526,6 +608,13 @@ const startGenericInternal = Effect.fnUntraced(function* (logic, options) {
|
|
|
526
608
|
const { detached, id: requestedId, onOutcome, onReady, onReadySync, onSnapshot, onStop, onStopSync, parent, runtime, sendParent: overrideSendParent } = options;
|
|
527
609
|
const sessionId = options.sessionId ?? (yield* runtime.nextSessionId);
|
|
528
610
|
const id = requestedId ?? sessionId;
|
|
611
|
+
const inspector = runtime.inspection;
|
|
612
|
+
const subject = inspector === undefined ? undefined : inspectionSubject(logic, id, sessionId);
|
|
613
|
+
const activity = inspector === undefined || options.activity === undefined
|
|
614
|
+
? undefined
|
|
615
|
+
: { ...options.activity, sessionId };
|
|
616
|
+
let initialEntryPaths;
|
|
617
|
+
let initialMicrosteps;
|
|
529
618
|
const queue = yield* Queue.unbounded();
|
|
530
619
|
const emissions = options.emissions ?? makeEmissionRuntime();
|
|
531
620
|
const termination = yield* Deferred.make();
|
|
@@ -534,6 +623,15 @@ const startGenericInternal = Effect.fnUntraced(function* (logic, options) {
|
|
|
534
623
|
let initializing = true;
|
|
535
624
|
let inFlightMessage;
|
|
536
625
|
const requestStop = Deferred.succeed(termination, { _tag: "Stopped" }).pipe(Effect.asVoid);
|
|
626
|
+
const offerDirect = (message) => Queue.offer(queue, message).pipe(Effect.flatMap((accepted) => accepted ? Effect.void : Effect.fail(new StoppedError())));
|
|
627
|
+
const offerInspected = inspector === undefined ? undefined : (event, source, causedBy, deferred) => Effect.suspend(() => {
|
|
628
|
+
const message = inspector.isActive()
|
|
629
|
+
? makeInspectedMessage(inspector, subject, event, source, causedBy, deferred)
|
|
630
|
+
: deferred === undefined
|
|
631
|
+
? event
|
|
632
|
+
: { [AcknowledgedMessageTypeId]: true, event, deferred };
|
|
633
|
+
return offerDirect(message).pipe(Effect.tap(() => Effect.sync(() => publishInspectedSent(inspector, subject, message))));
|
|
634
|
+
});
|
|
537
635
|
const self = {
|
|
538
636
|
id,
|
|
539
637
|
sessionId,
|
|
@@ -545,17 +643,21 @@ const startGenericInternal = Effect.fnUntraced(function* (logic, options) {
|
|
|
545
643
|
stop: Effect.suspend(() => initializing
|
|
546
644
|
? requestStop
|
|
547
645
|
: requestStop.pipe(Effect.andThen(Effect.never))),
|
|
548
|
-
send:
|
|
646
|
+
send: inspector === undefined
|
|
647
|
+
? (event) => offerDirect(event)
|
|
648
|
+
: (event) => offerInspected(event, undefined, undefined),
|
|
649
|
+
...(inspector === undefined
|
|
650
|
+
? undefined
|
|
651
|
+
: { inspectionSubject: subject, sendInspected: offerInspected })
|
|
549
652
|
};
|
|
550
653
|
const sendAcknowledged = logic.execution?._tag !== "Compiled"
|
|
551
654
|
? undefined
|
|
552
|
-
: (event) => Effect.uninterruptibleMask((restore) => Deferred.make().pipe(Effect.flatMap((deferred) =>
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
: Effect.fail(new StoppedError())))), Effect.map((delivery) => delivery)));
|
|
655
|
+
: (event) => Effect.uninterruptibleMask((restore) => Deferred.make().pipe(Effect.flatMap((deferred) => {
|
|
656
|
+
const offered = inspector === undefined
|
|
657
|
+
? offerDirect({ [AcknowledgedMessageTypeId]: true, event, deferred })
|
|
658
|
+
: offerInspected(event, undefined, undefined, deferred);
|
|
659
|
+
return offered.pipe(Effect.andThen(restore(Deferred.await(deferred))));
|
|
660
|
+
}), Effect.map((delivery) => delivery)));
|
|
559
661
|
let { changes: childChanges, close: closeChildren, get: getChild, owned: ownedChildren, sendTo, spawn, stop: stopChild } = childlessRuntime;
|
|
560
662
|
if (!executionIsChildless(logic.execution)) {
|
|
561
663
|
;
|
|
@@ -569,24 +671,68 @@ const startGenericInternal = Effect.fnUntraced(function* (logic, options) {
|
|
|
569
671
|
stop: stopChild
|
|
570
672
|
} = yield* makeChildRuntime(self, runtime));
|
|
571
673
|
}
|
|
572
|
-
const cleanupStartupFailure = (exit) =>
|
|
573
|
-
|
|
574
|
-
|
|
674
|
+
const cleanupStartupFailure = (exit) => {
|
|
675
|
+
if (Exit.isSuccess(exit))
|
|
676
|
+
return Effect.void;
|
|
677
|
+
if (inspector !== undefined) {
|
|
678
|
+
inspector.publishUnsafe(activity === undefined
|
|
679
|
+
? { _tag: "StartFailed", subject: subject, cause: exit.cause }
|
|
680
|
+
: { _tag: "ActivityStopped", subject: activity.owner, activity, exit });
|
|
681
|
+
}
|
|
682
|
+
return closeChildren(exit).pipe(Effect.andThen(emissions.close()), Effect.andThen(options.inspectionRoot === true && inspector !== undefined ? inspector.close : Effect.void));
|
|
683
|
+
};
|
|
575
684
|
const cleanup = onStopSync === undefined ? onStop ?? Effect.void : Effect.sync(onStopSync);
|
|
576
|
-
const
|
|
685
|
+
const currentCausation = inspector === undefined
|
|
686
|
+
? noCausation
|
|
687
|
+
: () => messageCausation(inFlightMessage, initializing);
|
|
688
|
+
const sendParent = overrideSendParent ?? (parent === undefined
|
|
689
|
+
? noParentSend
|
|
690
|
+
: inspector === undefined
|
|
691
|
+
? parent.send
|
|
692
|
+
: (event) => sendMachineTarget(parent, event, subject, currentCausation()));
|
|
693
|
+
const emit = inspector === undefined
|
|
694
|
+
? emissions.emit
|
|
695
|
+
: (event) => emissions.emit(event).pipe(Effect.tap(() => Effect.sync(() => inspector.publishUnsafe({
|
|
696
|
+
_tag: "Emitted",
|
|
697
|
+
subject: subject,
|
|
698
|
+
emission: event,
|
|
699
|
+
causedBy: currentCausation()
|
|
700
|
+
}))));
|
|
701
|
+
const sendToTarget = inspector === undefined
|
|
702
|
+
? ((target, event) => isMachineTarget(target) ? target.send(event) : sendTo(target, event))
|
|
703
|
+
: ((target, event) => isMachineTarget(target)
|
|
704
|
+
? sendMachineTarget(target, event, subject, currentCausation())
|
|
705
|
+
: sendTo(target, event, subject, currentCausation()));
|
|
577
706
|
const scope = {
|
|
578
707
|
self,
|
|
579
708
|
parent,
|
|
580
709
|
spawn,
|
|
581
710
|
sendParent,
|
|
582
|
-
emit
|
|
583
|
-
sendTo:
|
|
711
|
+
emit,
|
|
712
|
+
sendTo: sendToTarget,
|
|
584
713
|
stopChild,
|
|
585
714
|
failCause: (cause) => Deferred.succeed(termination, {
|
|
586
715
|
_tag: "Failure",
|
|
587
716
|
cause: cause
|
|
588
|
-
}).pipe(Effect.asVoid)
|
|
717
|
+
}).pipe(Effect.asVoid),
|
|
718
|
+
inspectInitial: inspector === undefined
|
|
719
|
+
? noInspectInitial
|
|
720
|
+
: (paths, microsteps = []) => {
|
|
721
|
+
initialEntryPaths = paths;
|
|
722
|
+
initialMicrosteps = microsteps;
|
|
723
|
+
}
|
|
589
724
|
};
|
|
725
|
+
if (inspector !== undefined) {
|
|
726
|
+
inspector.publishUnsafe(activity === undefined
|
|
727
|
+
? {
|
|
728
|
+
_tag: "Created",
|
|
729
|
+
subject: subject,
|
|
730
|
+
parent: parent?.inspectionSubject,
|
|
731
|
+
origin: options.origin ?? { _tag: "Root" },
|
|
732
|
+
definition: logic.inspection?.definition
|
|
733
|
+
}
|
|
734
|
+
: { _tag: "ActivityStarted", subject: activity.owner, activity });
|
|
735
|
+
}
|
|
590
736
|
const initial = yield* logic.initial(scope).pipe(Effect.onExit(cleanupStartupFailure), Effect.ensuring(Effect.sync(() => {
|
|
591
737
|
initializing = false;
|
|
592
738
|
})));
|
|
@@ -599,6 +745,15 @@ const startGenericInternal = Effect.fnUntraced(function* (logic, options) {
|
|
|
599
745
|
state: initial
|
|
600
746
|
}
|
|
601
747
|
});
|
|
748
|
+
if (activity === undefined) {
|
|
749
|
+
inspector?.publishUnsafe({
|
|
750
|
+
_tag: "Initialized",
|
|
751
|
+
subject: subject,
|
|
752
|
+
snapshot: { status: "active", state: initial },
|
|
753
|
+
initialEntryPaths: initialEntryPaths ?? [],
|
|
754
|
+
microsteps: InspectionRuntime.microsteps({ microsteps: initialMicrosteps ?? [] })
|
|
755
|
+
});
|
|
756
|
+
}
|
|
602
757
|
const publishSnapshot = onSnapshot === undefined
|
|
603
758
|
? (snapshot) => snapshot.changes === undefined
|
|
604
759
|
? Effect.succeed(snapshot)
|
|
@@ -658,16 +813,46 @@ const startGenericInternal = Effect.fnUntraced(function* (logic, options) {
|
|
|
658
813
|
terminalizing: true,
|
|
659
814
|
changes: current.changes
|
|
660
815
|
})).pipe(Effect.flatMap(publishSnapshot), Effect.flatMap(completeIfTerminal), Effect.asVoid);
|
|
661
|
-
const
|
|
816
|
+
const setActiveStateDirect = (state) => updateSnapshot((snapshot) => Effect.succeed(snapshot.status === "active"
|
|
662
817
|
? {
|
|
663
818
|
status: "active",
|
|
664
819
|
state
|
|
665
820
|
}
|
|
666
821
|
: undefined)).pipe(Effect.asVoid);
|
|
822
|
+
const setActiveState = inspector === undefined ?
|
|
823
|
+
setActiveStateDirect :
|
|
824
|
+
(state) => SynchronizedRef.get(current).pipe(Effect.flatMap((before) => updateSnapshot((snapshot) => Effect.succeed(snapshot.status === "active"
|
|
825
|
+
? {
|
|
826
|
+
status: "active",
|
|
827
|
+
state
|
|
828
|
+
}
|
|
829
|
+
: undefined)).pipe(Effect.tap((after) => Effect.sync(() => {
|
|
830
|
+
if (logic.inspection?.kind === "Machine" || after === undefined)
|
|
831
|
+
return;
|
|
832
|
+
inspector.publishUnsafe({
|
|
833
|
+
_tag: "StateChanged",
|
|
834
|
+
subject: subject,
|
|
835
|
+
before: before.snapshot.state,
|
|
836
|
+
after: state,
|
|
837
|
+
causedByDeliveryId: inFlightMessage !== undefined && isAcknowledgedMessage(inFlightMessage)
|
|
838
|
+
? inFlightMessage.inspection?.deliveryId
|
|
839
|
+
: undefined
|
|
840
|
+
});
|
|
841
|
+
})))), Effect.asVoid);
|
|
667
842
|
const terminalizeWith = (snapshot, exit, completeDone) => {
|
|
668
843
|
const notifyOutcome = onOutcome === undefined || (snapshot.status === "stopped" && options.skipStoppedOutcome === true)
|
|
669
844
|
? Effect.void
|
|
670
845
|
: Effect.suspend(() => onOutcome(classifyOutcome(snapshot))).pipe(Effect.exit, Effect.asVoid);
|
|
846
|
+
const closeEmissionsAndInspect = inspector === undefined
|
|
847
|
+
? emissions.close()
|
|
848
|
+
: emissions.close().pipe(Effect.andThen(Effect.sync(() => inspector.publishUnsafe(activity === undefined
|
|
849
|
+
? { _tag: "Terminated", subject: subject, snapshot }
|
|
850
|
+
: {
|
|
851
|
+
_tag: "ActivityStopped",
|
|
852
|
+
subject: activity.owner,
|
|
853
|
+
activity,
|
|
854
|
+
exit: snapshot.status === "stopped" ? Exit.interrupt() : exit
|
|
855
|
+
}))));
|
|
671
856
|
return Effect.uninterruptible(Effect.sync(() => {
|
|
672
857
|
while (true) {
|
|
673
858
|
const pending = Queue.takeUnsafe(queue);
|
|
@@ -675,7 +860,7 @@ const startGenericInternal = Effect.fnUntraced(function* (logic, options) {
|
|
|
675
860
|
break;
|
|
676
861
|
stopAcknowledgedMessage(pending.value);
|
|
677
862
|
}
|
|
678
|
-
}).pipe(Effect.andThen(Queue.shutdown(queue)), Effect.andThen(closeChildren(exit)), Effect.andThen(setAndPublishSnapshot(snapshot)), Effect.andThen(
|
|
863
|
+
}).pipe(Effect.andThen(Queue.shutdown(queue)), Effect.andThen(closeChildren(exit)), Effect.andThen(setAndPublishSnapshot(snapshot)), Effect.andThen(closeEmissionsAndInspect), Effect.andThen(Effect.sync(() => {
|
|
679
864
|
if (Exit.isFailure(exit)) {
|
|
680
865
|
failAcknowledgedMessage(inFlightMessage, exit.cause);
|
|
681
866
|
}
|
|
@@ -683,7 +868,7 @@ const startGenericInternal = Effect.fnUntraced(function* (logic, options) {
|
|
|
683
868
|
stopAcknowledgedMessage(inFlightMessage);
|
|
684
869
|
}
|
|
685
870
|
inFlightMessage = undefined;
|
|
686
|
-
})), Effect.andThen(notifyOutcome), Effect.andThen(cleanup), Effect.andThen(completeDone)));
|
|
871
|
+
})), Effect.andThen(notifyOutcome), Effect.andThen(cleanup), Effect.andThen(options.inspectionRoot === true && inspector !== undefined ? inspector.close : Effect.void), Effect.andThen(completeDone)));
|
|
687
872
|
};
|
|
688
873
|
const reserveStoppedSnapshot = reserveTerminalSnapshot((snapshot) => ({
|
|
689
874
|
status: "stopped",
|
|
@@ -726,20 +911,52 @@ const startGenericInternal = Effect.fnUntraced(function* (logic, options) {
|
|
|
726
911
|
inFlightMessage = undefined;
|
|
727
912
|
}
|
|
728
913
|
};
|
|
914
|
+
const receive = inspector === undefined || logic.execution?._tag === "Compiled"
|
|
915
|
+
? Queue.take(queue).pipe(Effect.map(messageEvent))
|
|
916
|
+
: Queue.take(queue).pipe(Effect.tap((message) => Effect.sync(() => {
|
|
917
|
+
inFlightMessage = message;
|
|
918
|
+
})), Effect.map(messageEvent));
|
|
919
|
+
const poll = inspector === undefined || logic.execution?._tag === "Compiled"
|
|
920
|
+
? Queue.poll(queue).pipe(Effect.map(Option.map(messageEvent)))
|
|
921
|
+
: Queue.poll(queue).pipe(Effect.tap((message) => Effect.sync(() => {
|
|
922
|
+
if (Option.isSome(message))
|
|
923
|
+
inFlightMessage = message.value;
|
|
924
|
+
})), Effect.map(Option.map(messageEvent)));
|
|
925
|
+
const updateStateDirect = (f) => updateSnapshot((snapshot) => snapshot.status === "active"
|
|
926
|
+
? f(snapshot.state).pipe(Effect.map((state) => ({
|
|
927
|
+
status: "active",
|
|
928
|
+
state
|
|
929
|
+
})))
|
|
930
|
+
: Effect.succeed(undefined)).pipe(Effect.asVoid);
|
|
931
|
+
const updateState = inspector === undefined
|
|
932
|
+
? updateStateDirect
|
|
933
|
+
: (f) => SynchronizedRef.get(current).pipe(Effect.flatMap((before) => updateSnapshot((snapshot) => snapshot.status === "active"
|
|
934
|
+
? f(snapshot.state).pipe(Effect.map((state) => ({
|
|
935
|
+
status: "active",
|
|
936
|
+
state
|
|
937
|
+
})))
|
|
938
|
+
: Effect.succeed(undefined)).pipe(Effect.tap((after) => Effect.sync(() => {
|
|
939
|
+
if (logic.inspection?.kind === "Machine" || after?.status !== "active")
|
|
940
|
+
return;
|
|
941
|
+
inspector.publishUnsafe({
|
|
942
|
+
_tag: "StateChanged",
|
|
943
|
+
subject: subject,
|
|
944
|
+
before: before.snapshot.state,
|
|
945
|
+
after: after.state,
|
|
946
|
+
causedByDeliveryId: inFlightMessage !== undefined && isAcknowledgedMessage(inFlightMessage)
|
|
947
|
+
? inFlightMessage.inspection?.deliveryId
|
|
948
|
+
: undefined
|
|
949
|
+
});
|
|
950
|
+
})))), Effect.asVoid);
|
|
729
951
|
const context = {
|
|
730
952
|
...scope,
|
|
731
953
|
...(logic.execution?._tag === "Compiled" && !logic.execution.childless ? { ownedChildren } : undefined),
|
|
732
954
|
...acknowledgedContext,
|
|
733
|
-
receive
|
|
734
|
-
poll
|
|
955
|
+
receive,
|
|
956
|
+
poll,
|
|
735
957
|
state: SynchronizedRef.get(current).pipe(Effect.map((current) => current.snapshot.state)),
|
|
736
958
|
setState: setActiveState,
|
|
737
|
-
updateState
|
|
738
|
-
? f(snapshot.state).pipe(Effect.map((state) => ({
|
|
739
|
-
status: "active",
|
|
740
|
-
state
|
|
741
|
-
})))
|
|
742
|
-
: Effect.succeed(undefined)).pipe(Effect.asVoid)
|
|
959
|
+
updateState
|
|
743
960
|
};
|
|
744
961
|
const getOrCreateChanges = SynchronizedRef.modifyEffect(current, (current) => {
|
|
745
962
|
if (current.snapshot.status !== "active") {
|
|
@@ -765,6 +982,9 @@ const startGenericInternal = Effect.fnUntraced(function* (logic, options) {
|
|
|
765
982
|
const ref = {
|
|
766
983
|
id,
|
|
767
984
|
sessionId,
|
|
985
|
+
...(inspector === undefined
|
|
986
|
+
? undefined
|
|
987
|
+
: { inspectionSubject: subject, sendInspected: offerInspected }),
|
|
768
988
|
state: SynchronizedRef.get(current).pipe(Effect.map((current) => current.snapshot.state)),
|
|
769
989
|
snapshot: SynchronizedRef.get(current).pipe(Effect.map((current) => current.snapshot)),
|
|
770
990
|
changes: changesStream,
|
|
@@ -852,7 +1072,11 @@ class CompiledProcess {
|
|
|
852
1072
|
services;
|
|
853
1073
|
id;
|
|
854
1074
|
sessionId;
|
|
1075
|
+
inspectionSubject;
|
|
855
1076
|
send;
|
|
1077
|
+
sendInspected(event, source, causedBy) {
|
|
1078
|
+
return this.offerEvent(event, source, causedBy);
|
|
1079
|
+
}
|
|
856
1080
|
[acknowledgedSend](event) {
|
|
857
1081
|
return this.sendAcknowledgedEffect(event);
|
|
858
1082
|
}
|
|
@@ -884,41 +1108,125 @@ class CompiledProcess {
|
|
|
884
1108
|
inFlightMessage;
|
|
885
1109
|
externalEmissions;
|
|
886
1110
|
emissionsPubSub;
|
|
1111
|
+
activity;
|
|
1112
|
+
initialEntryPaths;
|
|
1113
|
+
initialMicrosteps;
|
|
1114
|
+
initializing;
|
|
887
1115
|
constructor(logic, options, services, sessionId) {
|
|
888
1116
|
this.logic = logic;
|
|
889
1117
|
this.options = options;
|
|
890
1118
|
this.services = services;
|
|
891
1119
|
this.sessionId = sessionId;
|
|
892
1120
|
this.id = options.id ?? sessionId;
|
|
1121
|
+
const inspector = options.runtime.inspection;
|
|
1122
|
+
if (inspector !== undefined) {
|
|
1123
|
+
this.inspectionSubject = inspectionSubject(logic, this.id, sessionId);
|
|
1124
|
+
this.initializing = true;
|
|
1125
|
+
if (options.activity !== undefined)
|
|
1126
|
+
this.activity = { ...options.activity, sessionId };
|
|
1127
|
+
}
|
|
893
1128
|
this.externalEmissions = options.emissions;
|
|
894
|
-
this.send =
|
|
1129
|
+
this.send = inspector === undefined
|
|
1130
|
+
? (event) => this.offerMessage(event)
|
|
1131
|
+
: (event) => this.offerEvent(event, undefined, undefined);
|
|
895
1132
|
this.address = {
|
|
896
1133
|
id: this.id,
|
|
897
1134
|
sessionId,
|
|
898
1135
|
stop: Effect.suspend(() => this.stopFromProcess()),
|
|
899
|
-
send: this.send
|
|
1136
|
+
send: this.send,
|
|
1137
|
+
...(inspector === undefined
|
|
1138
|
+
? undefined
|
|
1139
|
+
: {
|
|
1140
|
+
inspectionSubject: this.inspectionSubject,
|
|
1141
|
+
sendInspected: (event, source, causedBy) => this.offerEvent(event, source, causedBy)
|
|
1142
|
+
})
|
|
900
1143
|
};
|
|
901
1144
|
}
|
|
1145
|
+
get inspector() {
|
|
1146
|
+
return this.options.runtime.inspection;
|
|
1147
|
+
}
|
|
1148
|
+
causation() {
|
|
1149
|
+
return messageCausation(this.inFlightMessage, this.initializing === true);
|
|
1150
|
+
}
|
|
1151
|
+
publishCreated() {
|
|
1152
|
+
const inspector = this.inspector;
|
|
1153
|
+
const subject = this.inspectionSubject;
|
|
1154
|
+
if (inspector === undefined || subject === undefined)
|
|
1155
|
+
return;
|
|
1156
|
+
inspector.publishUnsafe(this.activity === undefined
|
|
1157
|
+
? {
|
|
1158
|
+
_tag: "Created",
|
|
1159
|
+
subject,
|
|
1160
|
+
parent: this.options.parent?.inspectionSubject,
|
|
1161
|
+
origin: this.options.origin ?? { _tag: "Root" },
|
|
1162
|
+
definition: this.logic.inspection?.definition
|
|
1163
|
+
}
|
|
1164
|
+
: { _tag: "ActivityStarted", subject: this.activity.owner, activity: this.activity });
|
|
1165
|
+
}
|
|
1166
|
+
publishInitialized(state) {
|
|
1167
|
+
this.initializing = false;
|
|
1168
|
+
if (this.activity !== undefined)
|
|
1169
|
+
return;
|
|
1170
|
+
const inspector = this.inspector;
|
|
1171
|
+
const subject = this.inspectionSubject;
|
|
1172
|
+
if (inspector === undefined || subject === undefined)
|
|
1173
|
+
return;
|
|
1174
|
+
inspector.publishUnsafe({
|
|
1175
|
+
_tag: "Initialized",
|
|
1176
|
+
subject,
|
|
1177
|
+
snapshot: { status: "active", state },
|
|
1178
|
+
initialEntryPaths: this.initialEntryPaths ?? [],
|
|
1179
|
+
microsteps: InspectionRuntime.microsteps({ microsteps: this.initialMicrosteps ?? [] })
|
|
1180
|
+
});
|
|
1181
|
+
}
|
|
1182
|
+
publishStartFailed(cause) {
|
|
1183
|
+
this.initializing = false;
|
|
1184
|
+
const inspector = this.inspector;
|
|
1185
|
+
const subject = this.inspectionSubject;
|
|
1186
|
+
if (inspector === undefined || subject === undefined)
|
|
1187
|
+
return;
|
|
1188
|
+
inspector.publishUnsafe(this.activity === undefined
|
|
1189
|
+
? { _tag: "StartFailed", subject, cause }
|
|
1190
|
+
: {
|
|
1191
|
+
_tag: "ActivityStopped",
|
|
1192
|
+
subject: this.activity.owner,
|
|
1193
|
+
activity: this.activity,
|
|
1194
|
+
exit: Exit.failCause(cause)
|
|
1195
|
+
});
|
|
1196
|
+
}
|
|
902
1197
|
get execution() {
|
|
903
1198
|
return this.logic.execution;
|
|
904
1199
|
}
|
|
905
1200
|
initializeCompiledSync() {
|
|
1201
|
+
this.publishCreated();
|
|
906
1202
|
if (!this.execution.childless) {
|
|
907
1203
|
this.childRuntime = makeChildRuntimeSync(this.address, this.options.runtime, this.services);
|
|
908
1204
|
}
|
|
909
1205
|
const parent = this.options.parent;
|
|
910
|
-
const sendParent = this.options.sendParent ?? (parent === undefined
|
|
1206
|
+
const sendParent = this.options.sendParent ?? (parent === undefined
|
|
1207
|
+
? noParentSend
|
|
1208
|
+
: this.inspector === undefined
|
|
1209
|
+
? parent.send
|
|
1210
|
+
: (event) => sendMachineTarget(parent, event, this.inspectionSubject, this.causation()));
|
|
911
1211
|
this.processScope = {
|
|
912
1212
|
self: this.address,
|
|
913
1213
|
parent,
|
|
914
1214
|
spawn: this.childRuntime.spawn,
|
|
915
1215
|
sendParent,
|
|
916
1216
|
emit: (event) => this.emitEvent(event),
|
|
917
|
-
sendTo: ((target, event) =>
|
|
918
|
-
?
|
|
919
|
-
|
|
1217
|
+
sendTo: ((target, event) => isMachineTarget(target)
|
|
1218
|
+
? this.inspector === undefined
|
|
1219
|
+
? target.send(event)
|
|
1220
|
+
: sendMachineTarget(target, event, this.inspectionSubject, this.causation())
|
|
1221
|
+
: this.childRuntime.sendTo(target, event, this.inspectionSubject, this.causation())),
|
|
920
1222
|
stopChild: this.childRuntime.stop,
|
|
921
|
-
failCause: (cause) => this.failCause(cause)
|
|
1223
|
+
failCause: (cause) => this.failCause(cause),
|
|
1224
|
+
inspectInitial: this.inspector === undefined
|
|
1225
|
+
? noInspectInitial
|
|
1226
|
+
: (paths, microsteps = []) => {
|
|
1227
|
+
this.initialEntryPaths = paths;
|
|
1228
|
+
this.initialMicrosteps = microsteps;
|
|
1229
|
+
}
|
|
922
1230
|
};
|
|
923
1231
|
const compiledInitial = this.execution.initialSync;
|
|
924
1232
|
let initialized;
|
|
@@ -927,6 +1235,7 @@ class CompiledProcess {
|
|
|
927
1235
|
}
|
|
928
1236
|
catch (error) {
|
|
929
1237
|
this.runState = "Idle";
|
|
1238
|
+
this.publishStartFailed(Cause.fail(error));
|
|
930
1239
|
return Effect.fail(error);
|
|
931
1240
|
}
|
|
932
1241
|
this.runState = "Idle";
|
|
@@ -936,6 +1245,7 @@ class CompiledProcess {
|
|
|
936
1245
|
changes: undefined,
|
|
937
1246
|
snapshot: { status: "active", state: initialized.state }
|
|
938
1247
|
};
|
|
1248
|
+
this.publishInitialized(initialized.state);
|
|
939
1249
|
this.compiledContext = new CompiledProcessContextImpl(this.processScope, this.childRuntime.owned, this);
|
|
940
1250
|
if ("executionState" in initialized) {
|
|
941
1251
|
this.compiledContext.executionState = initialized.executionState;
|
|
@@ -957,29 +1267,46 @@ class CompiledProcess {
|
|
|
957
1267
|
initialize() {
|
|
958
1268
|
const self = this;
|
|
959
1269
|
return Effect.gen(function* () {
|
|
1270
|
+
self.publishCreated();
|
|
960
1271
|
if (!self.execution.childless) {
|
|
961
1272
|
self.childRuntime = yield* makeChildRuntime(self.address, self.options.runtime, self.services);
|
|
962
1273
|
}
|
|
963
1274
|
const parent = self.options.parent;
|
|
964
|
-
const sendParent = self.options.sendParent ?? (parent === undefined
|
|
1275
|
+
const sendParent = self.options.sendParent ?? (parent === undefined
|
|
1276
|
+
? noParentSend
|
|
1277
|
+
: self.inspector === undefined
|
|
1278
|
+
? parent.send
|
|
1279
|
+
: (event) => sendMachineTarget(parent, event, self.inspectionSubject, self.causation()));
|
|
965
1280
|
self.processScope = {
|
|
966
1281
|
self: self.address,
|
|
967
1282
|
parent,
|
|
968
1283
|
spawn: self.childRuntime.spawn,
|
|
969
1284
|
sendParent,
|
|
970
1285
|
emit: (event) => self.emitEvent(event),
|
|
971
|
-
sendTo: ((target, event) =>
|
|
972
|
-
?
|
|
973
|
-
|
|
1286
|
+
sendTo: ((target, event) => isMachineTarget(target)
|
|
1287
|
+
? self.inspector === undefined
|
|
1288
|
+
? target.send(event)
|
|
1289
|
+
: sendMachineTarget(target, event, self.inspectionSubject, self.causation())
|
|
1290
|
+
: self.childRuntime.sendTo(target, event, self.inspectionSubject, self.causation())),
|
|
974
1291
|
stopChild: self.childRuntime.stop,
|
|
975
|
-
failCause: (cause) => self.failCause(cause)
|
|
1292
|
+
failCause: (cause) => self.failCause(cause),
|
|
1293
|
+
inspectInitial: self.inspector === undefined
|
|
1294
|
+
? noInspectInitial
|
|
1295
|
+
: (paths, microsteps = []) => {
|
|
1296
|
+
self.initialEntryPaths = paths;
|
|
1297
|
+
self.initialMicrosteps = microsteps;
|
|
1298
|
+
}
|
|
976
1299
|
};
|
|
977
1300
|
const cleanupStartupFailure = (exit) => Exit.isFailure(exit) ? self.childRuntime.close(exit) : Effect.void;
|
|
978
1301
|
const compiledInitial = self.execution.initial;
|
|
979
1302
|
const initializeEffect = compiledInitial === undefined
|
|
980
1303
|
? self.logic.initial(self.processScope).pipe(Effect.map((state) => ({ state, done: undefined, output: undefined })))
|
|
981
1304
|
: compiledInitial(self.processScope);
|
|
982
|
-
const initialized = yield* initializeEffect.pipe(Effect.onExit(
|
|
1305
|
+
const initialized = yield* initializeEffect.pipe(Effect.onExit((exit) => {
|
|
1306
|
+
if (Exit.isFailure(exit))
|
|
1307
|
+
self.publishStartFailed(exit.cause);
|
|
1308
|
+
return cleanupStartupFailure(exit);
|
|
1309
|
+
}), Effect.ensuring(Effect.sync(() => {
|
|
983
1310
|
self.runState = "Idle";
|
|
984
1311
|
})));
|
|
985
1312
|
const initial = initialized.state;
|
|
@@ -989,6 +1316,7 @@ class CompiledProcess {
|
|
|
989
1316
|
changes: undefined,
|
|
990
1317
|
snapshot: { status: "active", state: initial }
|
|
991
1318
|
};
|
|
1319
|
+
self.publishInitialized(initial);
|
|
992
1320
|
if (self.execution.drain._tag === "Process") {
|
|
993
1321
|
self.processContext = {
|
|
994
1322
|
...self.processScope,
|
|
@@ -1103,11 +1431,19 @@ class CompiledProcess {
|
|
|
1103
1431
|
: Effect.void));
|
|
1104
1432
|
}
|
|
1105
1433
|
sendAcknowledgedEffect(event) {
|
|
1106
|
-
return Effect.uninterruptibleMask((restore) => Deferred.make().pipe(Effect.flatMap((deferred) => this.
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1434
|
+
return Effect.uninterruptibleMask((restore) => Deferred.make().pipe(Effect.flatMap((deferred) => this.offerEvent(event, undefined, undefined, deferred).pipe(Effect.andThen(restore(Deferred.await(deferred)))))));
|
|
1435
|
+
}
|
|
1436
|
+
offerEvent(event, source, causedBy, deferred) {
|
|
1437
|
+
return Effect.suspend(() => {
|
|
1438
|
+
const inspector = this.inspector;
|
|
1439
|
+
const subject = this.inspectionSubject;
|
|
1440
|
+
const message = inspector?.isActive() === true && subject !== undefined
|
|
1441
|
+
? makeInspectedMessage(inspector, subject, event, source, causedBy, deferred)
|
|
1442
|
+
: deferred === undefined
|
|
1443
|
+
? event
|
|
1444
|
+
: { [AcknowledgedMessageTypeId]: true, event, deferred };
|
|
1445
|
+
return this.offerMessage(message);
|
|
1446
|
+
});
|
|
1111
1447
|
}
|
|
1112
1448
|
offerMessage(message) {
|
|
1113
1449
|
return Effect.uninterruptible(Effect.suspend(() => {
|
|
@@ -1115,6 +1451,10 @@ class CompiledProcess {
|
|
|
1115
1451
|
return Effect.fail(new StoppedError());
|
|
1116
1452
|
}
|
|
1117
1453
|
offerCompactMailbox(this.mailbox, message);
|
|
1454
|
+
const inspector = this.inspector;
|
|
1455
|
+
const subject = this.inspectionSubject;
|
|
1456
|
+
if (inspector !== undefined && subject !== undefined)
|
|
1457
|
+
publishInspectedSent(inspector, subject, message);
|
|
1118
1458
|
this.offerRevision += 1;
|
|
1119
1459
|
if (this.runState === "Draining") {
|
|
1120
1460
|
return Effect.void;
|
|
@@ -1153,6 +1493,7 @@ class CompiledProcess {
|
|
|
1153
1493
|
this.lifecycle !== "Active" ||
|
|
1154
1494
|
(this.options.onOutcome !== undefined && this.options.skipStoppedOutcome !== true) ||
|
|
1155
1495
|
this.options.onStop !== undefined ||
|
|
1496
|
+
this.inspector !== undefined ||
|
|
1156
1497
|
this.current.changes !== undefined ||
|
|
1157
1498
|
this.current.terminalizing || this.current.snapshot.status !== "active") {
|
|
1158
1499
|
return false;
|
|
@@ -1278,9 +1619,21 @@ class CompiledProcess {
|
|
|
1278
1619
|
(requested._tag === "Stopped" && this.options.skipStoppedOutcome === true)
|
|
1279
1620
|
? Effect.void
|
|
1280
1621
|
: Effect.suspend(() => this.options.onOutcome(classifyOutcome(snapshot))).pipe(Effect.exit, Effect.asVoid);
|
|
1622
|
+
const inspector = this.inspector;
|
|
1623
|
+
const subject = this.inspectionSubject;
|
|
1624
|
+
const closeEmissionsAndInspect = inspector === undefined || subject === undefined
|
|
1625
|
+
? this.closeEmissions()
|
|
1626
|
+
: this.closeEmissions().pipe(Effect.andThen(Effect.sync(() => inspector.publishUnsafe(this.activity === undefined
|
|
1627
|
+
? { _tag: "Terminated", subject, snapshot }
|
|
1628
|
+
: {
|
|
1629
|
+
_tag: "ActivityStopped",
|
|
1630
|
+
subject: this.activity.owner,
|
|
1631
|
+
activity: this.activity,
|
|
1632
|
+
exit: snapshot.status === "stopped" ? Exit.interrupt() : exit
|
|
1633
|
+
}))));
|
|
1281
1634
|
return Effect.uninterruptible(Effect.sync(() => {
|
|
1282
1635
|
closeCompactMailbox(this.mailbox);
|
|
1283
|
-
}).pipe(Effect.andThen(this.childRuntime.close(exit)), Effect.andThen(this.setAndPublishSnapshot(snapshot)), Effect.andThen(
|
|
1636
|
+
}).pipe(Effect.andThen(this.childRuntime.close(exit)), Effect.andThen(this.setAndPublishSnapshot(snapshot)), Effect.andThen(closeEmissionsAndInspect), Effect.andThen(Effect.sync(() => {
|
|
1284
1637
|
if (requested._tag === "Failure") {
|
|
1285
1638
|
failAcknowledgedMessage(this.inFlightMessage, requested.cause);
|
|
1286
1639
|
}
|
|
@@ -1288,7 +1641,9 @@ class CompiledProcess {
|
|
|
1288
1641
|
stopAcknowledgedMessage(this.inFlightMessage);
|
|
1289
1642
|
}
|
|
1290
1643
|
this.inFlightMessage = undefined;
|
|
1291
|
-
})), Effect.andThen(notifyOutcome), Effect.andThen(this.options.onStop ?? Effect.void), Effect.andThen(
|
|
1644
|
+
})), Effect.andThen(notifyOutcome), Effect.andThen(this.options.onStop ?? Effect.void), Effect.andThen(this.options.inspectionRoot === true && this.inspector !== undefined
|
|
1645
|
+
? this.inspector.close
|
|
1646
|
+
: Effect.void), Effect.andThen(Effect.sync(() => {
|
|
1292
1647
|
this.options.onStopSync?.();
|
|
1293
1648
|
this.runState = "Idle";
|
|
1294
1649
|
this.worker = undefined;
|
|
@@ -1320,11 +1675,21 @@ class CompiledProcess {
|
|
|
1320
1675
|
: PubSub.publish(snapshot.changes, Exit.succeed(undefined)).pipe(Effect.asVoid);
|
|
1321
1676
|
}
|
|
1322
1677
|
emitEvent(event) {
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1678
|
+
const publish = this.externalEmissions !== undefined ?
|
|
1679
|
+
this.externalEmissions.emit(event) :
|
|
1680
|
+
Effect.suspend(() => this.emissionsPubSub === undefined || this.emissionsPubSub === EmissionsClosed
|
|
1681
|
+
? Effect.void
|
|
1682
|
+
: PubSub.publish(this.emissionsPubSub, event).pipe(Effect.asVoid));
|
|
1683
|
+
const inspector = this.inspector;
|
|
1684
|
+
const subject = this.inspectionSubject;
|
|
1685
|
+
if (inspector === undefined || subject === undefined)
|
|
1686
|
+
return publish;
|
|
1687
|
+
return publish.pipe(Effect.tap(() => Effect.sync(() => inspector.publishUnsafe({
|
|
1688
|
+
_tag: "Emitted",
|
|
1689
|
+
subject,
|
|
1690
|
+
emission: event,
|
|
1691
|
+
causedBy: this.causation()
|
|
1692
|
+
}))));
|
|
1328
1693
|
}
|
|
1329
1694
|
shutdownEmissions() {
|
|
1330
1695
|
return this.closeEmissions();
|
|
@@ -1533,7 +1898,11 @@ const startCompactCompiledInternal = Effect.fnUntraced(function* (logic, options
|
|
|
1533
1898
|
options.onReady === undefined && options.onSnapshot === undefined
|
|
1534
1899
|
? process.initializeCompiledSync()
|
|
1535
1900
|
: process.initialize();
|
|
1536
|
-
return yield* initialize.pipe(Effect.onExit((exit) => Exit.isFailure(exit)
|
|
1901
|
+
return yield* initialize.pipe(Effect.onExit((exit) => Exit.isFailure(exit)
|
|
1902
|
+
? process.shutdownEmissions().pipe(Effect.andThen(options.inspectionRoot === true && options.runtime.inspection !== undefined
|
|
1903
|
+
? options.runtime.inspection.close
|
|
1904
|
+
: Effect.void))
|
|
1905
|
+
: Effect.void));
|
|
1537
1906
|
});
|
|
1538
1907
|
const startLogicInternal = ((logic, options) => logic.execution?._tag === "Compiled"
|
|
1539
1908
|
? startCompactCompiledInternal(logic, options)
|
|
@@ -1579,6 +1948,8 @@ export const startProcess = Effect.fnUntraced(function* (logic, options) {
|
|
|
1579
1948
|
const prepareProcessWithStrategy = Effect.fnUntraced(function* (logic, strategy, options) {
|
|
1580
1949
|
const runtime = yield* makeProcessRuntime;
|
|
1581
1950
|
const sessionId = yield* runtime.nextSessionId;
|
|
1951
|
+
const inspection = yield* InspectionRuntime.make(sessionId);
|
|
1952
|
+
runtime.inspection = inspection;
|
|
1582
1953
|
const emissions = makeEmissionRuntime();
|
|
1583
1954
|
const started = yield* Deferred.make();
|
|
1584
1955
|
const internalOptions = options === undefined
|
|
@@ -1586,14 +1957,18 @@ const prepareProcessWithStrategy = Effect.fnUntraced(function* (logic, strategy,
|
|
|
1586
1957
|
detached: true,
|
|
1587
1958
|
emissions,
|
|
1588
1959
|
runtime,
|
|
1589
|
-
sessionId
|
|
1960
|
+
sessionId,
|
|
1961
|
+
inspectionRoot: true,
|
|
1962
|
+
origin: { _tag: "Root" }
|
|
1590
1963
|
}
|
|
1591
1964
|
: {
|
|
1592
1965
|
...options,
|
|
1593
1966
|
detached: true,
|
|
1594
1967
|
emissions,
|
|
1595
1968
|
runtime,
|
|
1596
|
-
sessionId
|
|
1969
|
+
sessionId,
|
|
1970
|
+
inspectionRoot: true,
|
|
1971
|
+
origin: { _tag: "Root" }
|
|
1597
1972
|
};
|
|
1598
1973
|
const initialize = strategy === "generic"
|
|
1599
1974
|
? startGenericInternal(logic, internalOptions)
|
|
@@ -1608,6 +1983,7 @@ const prepareProcessWithStrategy = Effect.fnUntraced(function* (logic, strategy,
|
|
|
1608
1983
|
sessionId,
|
|
1609
1984
|
changes: Stream.unwrap(Deferred.await(started).pipe(Effect.map((ref) => ref.changes))),
|
|
1610
1985
|
emissions: emissions.stream,
|
|
1986
|
+
inspection: inspection.stream,
|
|
1611
1987
|
start
|
|
1612
1988
|
};
|
|
1613
1989
|
});
|