anbaric-state-machine 1.0.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 +24 -0
- package/src/StateMachine.ts +158 -0
- package/src/actors/Agent.ts +16 -0
- package/src/actors/Code.ts +16 -0
- package/src/actors/Human.ts +16 -0
- package/src/auditing/Auditor.ts +25 -0
- package/src/auditing/AuditorTransaction.ts +29 -0
- package/src/index.ts +12 -0
- package/src/persistence/InMemoryJobPersistence.ts +37 -0
- package/src/persistence/JobPersistenceFactory.ts +17 -0
- package/src/scheduling/ConsumerFactory.ts +15 -0
- package/src/scheduling/InMemoryQueue.ts +29 -0
- package/src/scheduling/PullConsumer.ts +54 -0
- package/src/scheduling/QueueFactory.ts +17 -0
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "anbaric-state-machine",
|
|
3
|
+
"version": "1.0.0",
|
|
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
|
+
"license": "MIT",
|
|
6
|
+
"author": "chris@anbaric.ai",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "src/index.ts",
|
|
9
|
+
"types": "src/index.ts",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "vitest run"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"@types/node": "^26.2.0",
|
|
15
|
+
"typescript": "^7.0.2"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"anbaric-cloud": "^1.0.0",
|
|
19
|
+
"anbaric-tsapi": "^1.0.0"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"src"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import {Action, Actor, Consumer, Job, JobPersistence, PropertyDefinition, Queue, State} from "anbaric-tsapi";
|
|
2
|
+
import {JobPersistenceFactory} from "./persistence/JobPersistenceFactory";
|
|
3
|
+
import {QueueFactory} from "./scheduling/QueueFactory";
|
|
4
|
+
import {ConsumerFactory} from "./scheduling/ConsumerFactory";
|
|
5
|
+
import {Auditor} from "./auditing/Auditor";
|
|
6
|
+
|
|
7
|
+
class StateMachine {
|
|
8
|
+
|
|
9
|
+
private workflowId: string;
|
|
10
|
+
private states: Map<string, State>;
|
|
11
|
+
private startState: string;
|
|
12
|
+
private dataSchema: Map<string, PropertyDefinition>;
|
|
13
|
+
private persistence: JobPersistence;
|
|
14
|
+
private queue: Queue;
|
|
15
|
+
private consumer: Consumer;
|
|
16
|
+
|
|
17
|
+
constructor(workflowId : string, states : Array<State>, startState : string, dataSchema : Array<PropertyDefinition>, persistence : JobPersistence = JobPersistenceFactory.instance(), queue : Queue = QueueFactory.instance()) {
|
|
18
|
+
|
|
19
|
+
this.workflowId = workflowId;
|
|
20
|
+
this.states = new Map(states.map(state => [state.id, state]));
|
|
21
|
+
this.startState = startState;
|
|
22
|
+
this.dataSchema = new Map(dataSchema.map(property => [property.id, property]));
|
|
23
|
+
this.persistence = persistence;
|
|
24
|
+
this.queue = queue;
|
|
25
|
+
|
|
26
|
+
this.consumer = ConsumerFactory.instance(queue)
|
|
27
|
+
this.consumer.subscribe(workflowId, jobId => this.progressJob(jobId));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async startJob(properties?: Map<string, any>, actor? : Actor): Promise<Job> {
|
|
31
|
+
|
|
32
|
+
const job = new Job(crypto.randomUUID(), properties, this.startState, this.workflowId,
|
|
33
|
+
actor?.id ?? this.workflowId);
|
|
34
|
+
|
|
35
|
+
if (! this.validateProperties(properties ?? new Map(), true)) throw new Error("Invalid properties");
|
|
36
|
+
|
|
37
|
+
if (! this.authorizeActor(actor, job)) {
|
|
38
|
+
Auditor.instance().audit(job.id, actor, "Unauthorized start", null);
|
|
39
|
+
throw new Error("Unauthorized");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
await this.persistence.save(job);
|
|
43
|
+
|
|
44
|
+
await this.queue.enqueue(job.id, this.workflowId);
|
|
45
|
+
|
|
46
|
+
return job;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async updateJob(jobId : string, properties : Map<string, any>, actor : Actor) : Promise<void> {
|
|
50
|
+
|
|
51
|
+
if (! this.authorizeActor(actor, await this.persistence.retrieve(jobId))) {
|
|
52
|
+
Auditor.instance().audit(jobId, actor, "Unauthorized update", null);
|
|
53
|
+
throw new Error("Unauthorized");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (! this.validateProperties(properties, false)) throw new Error("Invalid properties");
|
|
57
|
+
|
|
58
|
+
await this.persistence.updateProperties(jobId, properties);
|
|
59
|
+
Auditor.instance().audit(jobId, actor, "Properties updated", Object.fromEntries(properties));
|
|
60
|
+
|
|
61
|
+
await this.queue.enqueue(jobId, this.workflowId);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async executeAction(jobId : string, action : Action) : Promise<void> {
|
|
65
|
+
const job = await this.persistence.retrieve(jobId);
|
|
66
|
+
|
|
67
|
+
if (! action.predicate(job)) throw new Error("Action predicate unmet");
|
|
68
|
+
|
|
69
|
+
if (! this.authorizeActor(action.actor, job)) {
|
|
70
|
+
Auditor.instance().audit(jobId, action.actor, "Unauthorized update", null);
|
|
71
|
+
throw new Error("Actor not authorized to execute action");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const newProperties = await action.run(job);
|
|
75
|
+
|
|
76
|
+
if (! this.validateProperties(newProperties, false)) {
|
|
77
|
+
Auditor.instance().audit(jobId, action.actor, "Invalid properties", Object.fromEntries(newProperties));
|
|
78
|
+
throw new Error("The action generated invalid properties");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
await this.persistence.updateProperties(jobId, newProperties);
|
|
82
|
+
Auditor.instance().audit(jobId, action.actor, "Properties updated", Object.fromEntries(newProperties));
|
|
83
|
+
|
|
84
|
+
await this.queue.enqueue(jobId, this.workflowId);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private validateProperties(properties : Map<string, any>, isNew : boolean) : boolean {
|
|
88
|
+
for (const [key, value] of properties) {
|
|
89
|
+
const definition = this.dataSchema.get(key);
|
|
90
|
+
if (! definition || ! definition.validation(value)) return false;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (! isNew) return true;
|
|
94
|
+
|
|
95
|
+
for (const [key, definition] of this.dataSchema) {
|
|
96
|
+
if (definition.required && ! properties.has(key)) return false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private async progressJob(jobId : string) : Promise<void> {
|
|
103
|
+
const auditTransaction = Auditor.instance().transaction();
|
|
104
|
+
let pristine = true;
|
|
105
|
+
|
|
106
|
+
const job = await this.persistence.retrieve(jobId);
|
|
107
|
+
const currentState = this.states.get(job.stateId!);
|
|
108
|
+
|
|
109
|
+
for (const action of currentState?.actions ?? []) {
|
|
110
|
+
if (! action.predicate(job)) continue;
|
|
111
|
+
|
|
112
|
+
if (! this.authorizeActor(action.actor, job)) {
|
|
113
|
+
auditTransaction.audit(jobId, action.actor, "Unauthorized update", null);
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const newProperties = await action.run(job);
|
|
118
|
+
|
|
119
|
+
if (! this.validateProperties(newProperties, false)) {
|
|
120
|
+
auditTransaction.audit(jobId, action.actor, "Invalid properties", Object.fromEntries(newProperties));
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
auditTransaction.audit(jobId, action.actor, "Properties updated", Object.fromEntries(newProperties));
|
|
125
|
+
newProperties.forEach((value, key) => {
|
|
126
|
+
pristine = false;
|
|
127
|
+
job.properties.set(key, value);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
for (const transition of currentState?.transitions ?? []) {
|
|
132
|
+
if (! this.states.has(transition.to)) continue;
|
|
133
|
+
if (job.transition(transition)) {
|
|
134
|
+
auditTransaction.audit(jobId, undefined, `Transitioned to "${transition.to}"`, null);
|
|
135
|
+
pristine = false;
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (! pristine) {
|
|
141
|
+
await this.persistence.save(job);
|
|
142
|
+
await this.queue.enqueue(job.id, this.workflowId);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
auditTransaction.flush();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async cleanUp() : Promise<void> {
|
|
149
|
+
await this.consumer.cleanUp();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
private authorizeActor(actor: Actor | undefined, job: Job) : boolean {
|
|
153
|
+
// TODO
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export { StateMachine }
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {Actor} from "anbaric-tsapi";
|
|
2
|
+
|
|
3
|
+
class Agent implements Actor {
|
|
4
|
+
|
|
5
|
+
readonly type = "AGENT" as const;
|
|
6
|
+
readonly id : string;
|
|
7
|
+
readonly role : string;
|
|
8
|
+
|
|
9
|
+
constructor(id : string, role : string) {
|
|
10
|
+
this.id = id;
|
|
11
|
+
this.role = role;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { Agent }
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {Actor} from "anbaric-tsapi";
|
|
2
|
+
|
|
3
|
+
class Code implements Actor {
|
|
4
|
+
|
|
5
|
+
readonly type = "CODE" as const;
|
|
6
|
+
readonly id : string;
|
|
7
|
+
readonly role : string;
|
|
8
|
+
|
|
9
|
+
constructor(id : string, role : string = "code") {
|
|
10
|
+
this.id = id;
|
|
11
|
+
this.role = role;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { Code }
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {Actor} from "anbaric-tsapi";
|
|
2
|
+
|
|
3
|
+
class Human implements Actor {
|
|
4
|
+
|
|
5
|
+
readonly type = "HUMAN" as const;
|
|
6
|
+
readonly id : string;
|
|
7
|
+
readonly role : string;
|
|
8
|
+
|
|
9
|
+
constructor(id : string, role : string) {
|
|
10
|
+
this.id = id;
|
|
11
|
+
this.role = role;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { Human }
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {Actor} from "anbaric-tsapi";
|
|
2
|
+
import {AuditorTransaction} from "./AuditorTransaction";
|
|
3
|
+
|
|
4
|
+
class Auditor {
|
|
5
|
+
|
|
6
|
+
private static singleton? : Auditor;
|
|
7
|
+
|
|
8
|
+
static instance() : Auditor {
|
|
9
|
+
if (!Auditor.singleton) {
|
|
10
|
+
Auditor.singleton = new Auditor();
|
|
11
|
+
}
|
|
12
|
+
return Auditor.singleton;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
audit(jobId : string, actor : Actor | undefined, changeDescription : string, details : any) : void {
|
|
16
|
+
console.log(`[${jobId}] ${actor?.id ?? "anonymous"} ${changeDescription} ${JSON.stringify(details ?? null)}`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
transaction() : AuditorTransaction {
|
|
20
|
+
return new AuditorTransaction(this);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export { Auditor }
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {Actor} from "anbaric-tsapi";
|
|
2
|
+
import type {Auditor} from "./Auditor";
|
|
3
|
+
|
|
4
|
+
type AuditEntry = {
|
|
5
|
+
jobId : string,
|
|
6
|
+
actor : Actor | undefined,
|
|
7
|
+
changeDescription : string,
|
|
8
|
+
details : any,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
class AuditorTransaction {
|
|
12
|
+
|
|
13
|
+
private entries = new Array<AuditEntry>();
|
|
14
|
+
|
|
15
|
+
constructor(private auditor : Auditor) {}
|
|
16
|
+
|
|
17
|
+
audit(jobId : string, actor : Actor | undefined, changeDescription : string, details : any) : void {
|
|
18
|
+
this.entries.push({ jobId, actor, changeDescription, details });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
flush() : void {
|
|
22
|
+
this.entries.forEach(entry =>
|
|
23
|
+
this.auditor.audit(entry.jobId, entry.actor, entry.changeDescription, entry.details));
|
|
24
|
+
this.entries = [];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export { AuditorTransaction }
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from "./StateMachine";
|
|
2
|
+
export * from "./actors/Agent";
|
|
3
|
+
export * from "./actors/Code";
|
|
4
|
+
export * from "./actors/Human";
|
|
5
|
+
export * from "./auditing/Auditor";
|
|
6
|
+
export * from "./auditing/AuditorTransaction";
|
|
7
|
+
export * from "./persistence/InMemoryJobPersistence";
|
|
8
|
+
export * from "./persistence/JobPersistenceFactory";
|
|
9
|
+
export * from "./scheduling/InMemoryQueue";
|
|
10
|
+
export * from "./scheduling/PullConsumer";
|
|
11
|
+
export * from "./scheduling/ConsumerFactory";
|
|
12
|
+
export * from "./scheduling/QueueFactory";
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {Job, JobPersistence} from "anbaric-tsapi";
|
|
2
|
+
|
|
3
|
+
class InMemoryJobPersistence implements JobPersistence {
|
|
4
|
+
|
|
5
|
+
private jobs = new Map<string, Job>();
|
|
6
|
+
|
|
7
|
+
async save(job : Job) : Promise<void> {
|
|
8
|
+
this.jobs.set(job.id, job);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async retrieve(id : string) : Promise<Job> {
|
|
12
|
+
const job = this.jobs.get(id);
|
|
13
|
+
if (!job) {
|
|
14
|
+
throw new Error(`No job found with id "${id}"`);
|
|
15
|
+
}
|
|
16
|
+
return job;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async delete(id : string) : Promise<void> {
|
|
20
|
+
this.jobs.delete(id);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async list(pageSize : number = 100, page : number = 0) : Promise<Array<Job>> {
|
|
24
|
+
return Array.from(this.jobs.values()).slice(page * pageSize, (page + 1) * pageSize);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async updateProperties(id : string, properties : Map<string, any>) : Promise<void> {
|
|
28
|
+
const job = await this.retrieve(id);
|
|
29
|
+
for (const [key, value] of properties) {
|
|
30
|
+
job.properties.set(key, value);
|
|
31
|
+
}
|
|
32
|
+
job.lastUpdated = new Date();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { InMemoryJobPersistence }
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {JobPersistence} from "anbaric-tsapi";
|
|
2
|
+
import {CloudJobPersistence} from "anbaric-cloud";
|
|
3
|
+
import {InMemoryJobPersistence} from "./InMemoryJobPersistence";
|
|
4
|
+
|
|
5
|
+
const JobPersistenceFactory = {
|
|
6
|
+
instance() : JobPersistence {
|
|
7
|
+
switch (process.env.ANBARIC_JOB_PERSISTENCE_TYPE) {
|
|
8
|
+
case "cloud":
|
|
9
|
+
return new CloudJobPersistence();
|
|
10
|
+
case "memory":
|
|
11
|
+
default:
|
|
12
|
+
return new InMemoryJobPersistence();
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export { JobPersistenceFactory };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {Consumer, Dequeue, Queue} from "anbaric-tsapi";
|
|
2
|
+
import {PushConsumer} from "anbaric-cloud";
|
|
3
|
+
import {PullConsumer} from "./PullConsumer";
|
|
4
|
+
|
|
5
|
+
const ConsumerFactory = {
|
|
6
|
+
instance(queue : Queue) : Consumer {
|
|
7
|
+
if (Dequeue.supports(queue)) {
|
|
8
|
+
return new PullConsumer(queue);
|
|
9
|
+
} else {
|
|
10
|
+
return new PushConsumer();
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { ConsumerFactory };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {Dequeue, QueueMessage} from "anbaric-tsapi";
|
|
2
|
+
|
|
3
|
+
class InMemoryQueue implements Dequeue {
|
|
4
|
+
|
|
5
|
+
private ready : Array<QueueMessage> = [];
|
|
6
|
+
private scheduled : Array<{ message : QueueMessage, due : Date }> = [];
|
|
7
|
+
|
|
8
|
+
async enqueue(jobId : string, workflowId : string) : Promise<void> {
|
|
9
|
+
this.ready.push({ jobId, workflowId });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async schedule(jobId : string, workflowId : string, due : Date) : Promise<void> {
|
|
13
|
+
this.scheduled.push({ message: { jobId, workflowId }, due });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async dequeueSome() : Promise<Array<QueueMessage>> {
|
|
17
|
+
const now = new Date();
|
|
18
|
+
const released = this.scheduled
|
|
19
|
+
.filter((entry) => entry.due <= now)
|
|
20
|
+
.sort((a, b) => a.due.getTime() - b.due.getTime());
|
|
21
|
+
this.scheduled = this.scheduled.filter((entry) => entry.due > now);
|
|
22
|
+
const messages = [...this.ready, ...released.map((entry) => entry.message)];
|
|
23
|
+
this.ready = [];
|
|
24
|
+
return messages;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export { InMemoryQueue }
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import {Consumer, Dequeue, QueueMessage} from "anbaric-tsapi";
|
|
2
|
+
|
|
3
|
+
type ProcessJob = (jobId : string) => Promise<void>;
|
|
4
|
+
|
|
5
|
+
class PullConsumer implements Consumer {
|
|
6
|
+
|
|
7
|
+
private subscribers = new Map<string, ProcessJob>();
|
|
8
|
+
private ticker? : NodeJS.Timeout;
|
|
9
|
+
private draining = false;
|
|
10
|
+
|
|
11
|
+
constructor(private queue : Dequeue, private pollIntervalMs : number = 1000) {}
|
|
12
|
+
|
|
13
|
+
subscribe(workflowId : string, processJob : ProcessJob) : void {
|
|
14
|
+
this.subscribers.set(workflowId, processJob);
|
|
15
|
+
if (!this.ticker) {
|
|
16
|
+
this.ticker = setInterval(() => void this.drain(), this.pollIntervalMs);
|
|
17
|
+
this.ticker.unref();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async cleanUp() : Promise<void> {
|
|
22
|
+
if (this.ticker) clearInterval(this.ticker);
|
|
23
|
+
this.ticker = undefined;
|
|
24
|
+
this.subscribers.clear();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
private async drain() : Promise<void> {
|
|
28
|
+
if (this.draining) return;
|
|
29
|
+
this.draining = true;
|
|
30
|
+
try {
|
|
31
|
+
for (const message of await this.queue.dequeueSome()) {
|
|
32
|
+
await this.forward(message);
|
|
33
|
+
}
|
|
34
|
+
} finally {
|
|
35
|
+
this.draining = false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private async forward(message : QueueMessage) : Promise<void> {
|
|
40
|
+
const processJob = this.subscribers.get(message.workflowId);
|
|
41
|
+
if (!processJob) {
|
|
42
|
+
await this.queue.enqueue(message.jobId, message.workflowId);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
await processJob(message.jobId);
|
|
47
|
+
} catch {
|
|
48
|
+
await this.queue.enqueue(message.jobId, message.workflowId);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { PullConsumer }
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {Queue} from "anbaric-tsapi";
|
|
2
|
+
import {CloudQueue} from "anbaric-cloud";
|
|
3
|
+
import {InMemoryQueue} from "./InMemoryQueue";
|
|
4
|
+
|
|
5
|
+
const QueueFactory = {
|
|
6
|
+
instance() : Queue {
|
|
7
|
+
switch (process.env.ANBARIC_QUEUE_TYPE) {
|
|
8
|
+
case "cloud":
|
|
9
|
+
return new CloudQueue();
|
|
10
|
+
case "memory":
|
|
11
|
+
default:
|
|
12
|
+
return new InMemoryQueue();
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export { QueueFactory };
|