chore(deps): Update xstate to v5.32.4 - #333
Conversation
e3790c6 to
6e13ead
Compare
|
I validated a non-blocking ordering regression in What the repro shows
jest.mocked(spawnInteractive).mockReturnValue({
actions: {
write: jest.fn(),
writeLine: jest.fn(),
stop: jest.fn(),
},
exitCode: Promise.resolve(0),
});
const states: string[] = [];
await cli.deploy({}, (state) => states.push(state.type));
expect(states).toEqual(["running"]);On this PR head, the assertion fails with This is technically an observable behavior regression from v4, but normal Terraform apply/destroy invocations emit stdout/stderr. Those events produce a later snapshot while the machine is still in So I see this as a non-blocking lifecycle hardening opportunity, rather than evidence of a current customer-facing failure. The practical difference for a real Terraform run is that Minimal fix validated locallyProcessing the actor's current snapshot once after subscribing restores the initial callback without changing the factory API: const handleSnapshot = (
snapshot: ReturnType<typeof service.getSnapshot>,
) => {
// existing transition handling
};
service.subscribe(handleSnapshot);
// The actor was already started by createService, so consume the
// snapshot whose transition may have preceded the subscription.
handleSnapshot(service.getSnapshot());I pushed the TDD sequence as two commits:
Branch: https://github.com/sakul-learning/cdk-terrain/tree/review/pr-333-xstate-running-repro Validation:
Given the realistic execution path and green existing CI, this is a suggestion rather than a requested change. |
so0k
left a comment
There was a problem hiding this comment.
Up to you if you want to address the non-block ordering concern (which may not be a real failure mode) - still need to rebase for conflict resolution
0344474 to
e74ea6d
Compare
Description
Bumps
xstatefrom4.38.3to5.32.4(latest) in@cdktn/cli-core, the only package that declares it.This is a major version bump (4.x → 5.x) and required migrating the deploy state machine, its consumer, and its tests to the reworked v5 API.
State machine (
deploy-machine.ts)createMachine<Ctx, Evt, State>(…)→setup({ types, actors }).createMachine(…). The generic-parameter form was replaced by thesetup()builder with atypesblock. ThepredictableActionArgumentsflag was dropped (predictable ordering is the default in v5) andservicesbecameactors.fromCallback. The v4(context, event) => (send, onReceive) => {…}factory becamefromCallback(({ sendBack, receive, input }) => …). Since v5 invoked actors receiveinputrather than the triggering event, the spawn config now flows in throughinvoke.input. The actor is built bymakeTerraformPtyService(spawn)so tests can inject a mock pty.send(…, { to })→sendTo(…);assign<Ctx, Evt>→assign. Action creators were split and theassignimplementation signature changed to a single argument.raise(…)→sendTo(({ self }) => self, …). The two internally re-emitted events (EXITEDon a missing variable, and theOVERRIDE_REJECTED_EXTERNALLYre-label of an external discard) are sent to self rather than raised. Raised events are internal micro-steps and do not surface through the inspection API, so the consumer would otherwise stop observing them.EXITEDtransitions and surfaced through the machine's rootoutput, so consumers read it off the settled snapshot rather than scraping it from an event. This also puts the previously-unusedDeployContext.exitCodefield to work.DeploySnapshot(SnapshotFrom<typeof deployMachine>) andDeployActor(ActorRefFrom<typeof deployMachine>) are exported for the consumer.Consumer (
terraform-cli.ts)This needed the most care, because v5 snapshots no longer expose the triggering event (
state.event):service.subscribe(…), which yields a fully-typed snapshot for the root actor only — replacingservice.onTransition(…). Because the factory starts the actor and sendsSTARTbefore we subscribe, the current snapshot is processed once immediately after subscribing so the initialidle → runningtransition is not missed.inspectcallback (the only source that still carries the triggering event), replacingservice.onEvent(…). The root actor is identified byactorRef.sessionId === rootId— self-contained within the inspection event, so it works even while inspection fires during startup before theservicebinding is initialized. Events are narrowed through the existingisDeployEventguard.interpret(…)→createActor(…, { inspect }). The actor is started explicitly before events are sent.waitForis imported fromxstateand its predicate usessnapshot.status === "done"; the exit code is read fromsnapshot.output;service.send("X")calls becameservice.send({ type: "X" }).Tests
deploy-machine.test.tswas migrated to match:interpret().onTransition→createActor().subscribe,withConfig({ services })→provide({ actors }),machine.transition→getNextSnapshot, and thestate.eventassertions rebuilt on the inspection API.deploysuite was added toterraform-cli.test.tscovering the previously-untesteddeploy()/handleServicepath:runningis reported even when the process exits immediately (the subscribe-ordering fix), a zero exit resolves without cancellation, and a non-zero exit rejects with the exit code (the final-state-output path).tsc --noEmitpasses cleanly on the package, and all 28 tests acrossdeploy-machine.test.tsandterraform-cli.test.tspass.Checklist