anbaric-state-machine 1.11.0 → 1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anbaric-state-machine",
3
- "version": "1.11.0",
3
+ "version": "1.13.0",
4
4
  "description": "This is the state machine library that one can use to add state management to an application. It will, by default, be locally runnable but can deployed to the Anbaric Cloud via the CLI",
5
5
  "license": "MIT",
6
6
  "author": "chris@anbaric.ai",
@@ -15,8 +15,8 @@
15
15
  "typescript": "^7.0.2"
16
16
  },
17
17
  "dependencies": {
18
- "anbaric-impl-cloud": "^1.11.0",
19
- "anbaric-tsapi": "^1.11.0"
18
+ "anbaric-impl-cloud": "^1.13.0",
19
+ "anbaric-tsapi": "^1.13.0"
20
20
  },
21
21
  "files": [
22
22
  "src"
@@ -24,8 +24,9 @@ class StateMachine {
24
24
  private queue: Queue;
25
25
  private consumer: Consumer;
26
26
  private machineActor: Code;
27
+ private sameStateDelayMs: number;
27
28
 
28
- constructor(workflowId : string, states : Array<State>, startState : string, dataSchema : Array<PropertyDefinition>, persistence : JobPersistence = JobPersistenceFactory.instance(), queue : Queue = QueueFactory.instance()) {
29
+ constructor(workflowId : string, states : Array<State>, startState : string, dataSchema : Array<PropertyDefinition>, persistence : JobPersistence = JobPersistenceFactory.instance(), queue : Queue = QueueFactory.instance(), sameStateDelayMs : number = 5 * 60_000) {
29
30
 
30
31
  this.workflowId = workflowId;
31
32
  this.states = new Map(states.map(state => [state.id, state]));
@@ -34,6 +35,7 @@ class StateMachine {
34
35
  this.persistence = persistence;
35
36
  this.queue = queue;
36
37
  this.machineActor = new Code(workflowId, "state-machine");
38
+ this.sameStateDelayMs = sameStateDelayMs;
37
39
 
38
40
  this.consumer = ConsumerFactory.instance(queue)
39
41
  this.consumer.subscribe(workflowId, jobId => this.progressJob(jobId));
@@ -111,8 +113,12 @@ class StateMachine {
111
113
  let pristine = true;
112
114
 
113
115
  const job = await this.persistence.retrieve(jobId, this.machineActor);
116
+ if (job.killed) return;
117
+
114
118
  const currentState = this.states.get(job.state);
115
119
 
120
+ if (currentState?.isTerminal) return;
121
+
116
122
  const involvedActors : Actor[] = [];
117
123
 
118
124
  for (const action of currentState?.actions ?? []) {
@@ -128,6 +134,7 @@ class StateMachine {
128
134
  console.warn(`[${this.workflowId}] action "${action.name}" set "${key}", which ${problem}, on job ${job.id} — skipping that property.`);
129
135
  continue;
130
136
  }
137
+ if (job.properties.has(key) && this.sameValue(job.properties.get(key), value)) continue;
131
138
  job.properties.set(key, value);
132
139
  pristine = false;
133
140
  applied = true;
@@ -146,13 +153,23 @@ class StateMachine {
146
153
  }
147
154
  }
148
155
 
149
- if (! pristine) {
150
- // TODO: persistence.save should have the ability to accept multiple actors for this case.
151
- await this.persistence.save(involvedActors[0] ?? this.machineActor, `Job ${job.id} progressed automatically`, job, job.properties, newState);
156
+ if (pristine) return;
157
+
158
+ // TODO: persistence.save should have the ability to accept multiple actors for this case.
159
+ await this.persistence.save(involvedActors[0] ?? this.machineActor, `Job ${job.id} progressed automatically`, job, job.properties, newState);
160
+
161
+ if (this.states.get(newState ?? job.state)?.isTerminal) return;
162
+ if (newState !== undefined) {
152
163
  await this.queue.enqueue(job.id, this.workflowId);
164
+ } else {
165
+ await this.queue.schedule(job.id, this.workflowId, new Date(Date.now() + this.sameStateDelayMs));
153
166
  }
154
167
  }
155
168
 
169
+ private sameValue(a : any, b : any) : boolean {
170
+ return a === b || JSON.stringify(a) === JSON.stringify(b);
171
+ }
172
+
156
173
  async cleanUp() : Promise<void> {
157
174
  await this.consumer.cleanUp();
158
175
  }