anbaric-state-machine 1.11.0 → 1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anbaric-state-machine",
3
- "version": "1.11.0",
3
+ "version": "1.12.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.12.0",
19
+ "anbaric-tsapi": "^1.12.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));
@@ -113,6 +115,8 @@ class StateMachine {
113
115
  const job = await this.persistence.retrieve(jobId, this.machineActor);
114
116
  const currentState = this.states.get(job.state);
115
117
 
118
+ if (currentState?.isTerminal) return;
119
+
116
120
  const involvedActors : Actor[] = [];
117
121
 
118
122
  for (const action of currentState?.actions ?? []) {
@@ -128,6 +132,7 @@ class StateMachine {
128
132
  console.warn(`[${this.workflowId}] action "${action.name}" set "${key}", which ${problem}, on job ${job.id} — skipping that property.`);
129
133
  continue;
130
134
  }
135
+ if (job.properties.has(key) && this.sameValue(job.properties.get(key), value)) continue;
131
136
  job.properties.set(key, value);
132
137
  pristine = false;
133
138
  applied = true;
@@ -146,13 +151,23 @@ class StateMachine {
146
151
  }
147
152
  }
148
153
 
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);
154
+ if (pristine) return;
155
+
156
+ // TODO: persistence.save should have the ability to accept multiple actors for this case.
157
+ await this.persistence.save(involvedActors[0] ?? this.machineActor, `Job ${job.id} progressed automatically`, job, job.properties, newState);
158
+
159
+ if (this.states.get(newState ?? job.state)?.isTerminal) return;
160
+ if (newState !== undefined) {
152
161
  await this.queue.enqueue(job.id, this.workflowId);
162
+ } else {
163
+ await this.queue.schedule(job.id, this.workflowId, new Date(Date.now() + this.sameStateDelayMs));
153
164
  }
154
165
  }
155
166
 
167
+ private sameValue(a : any, b : any) : boolean {
168
+ return a === b || JSON.stringify(a) === JSON.stringify(b);
169
+ }
170
+
156
171
  async cleanUp() : Promise<void> {
157
172
  await this.consumer.cleanUp();
158
173
  }