1
- import { inject , injectable , Lifecycle , scoped } from "tsyringe" ;
2
- import { log } from "@proto-kit/common" ;
1
+ import { inject , injectable } from "tsyringe" ;
2
+ import { log , mapSequential } from "@proto-kit/common" ;
3
3
4
4
import { Closeable , InstantiatedQueue , TaskQueue } from "../queue/TaskQueue" ;
5
5
@@ -12,68 +12,6 @@ const errors = {
12
12
) ,
13
13
} ;
14
14
15
- @injectable ( )
16
- // ResolutionScoped => We want a new instance every time we resolve it
17
- @scoped ( Lifecycle . ResolutionScoped )
18
- export class ConnectionHolder implements Closeable {
19
- private queues : {
20
- [ key : string ] : InstantiatedQueue ;
21
- } = { } ;
22
-
23
- private listeners : {
24
- [ key : string ] : {
25
- [ key : string ] : ( payload : TaskPayload ) => Promise < void > ;
26
- } ;
27
- } = { } ;
28
-
29
- public constructor (
30
- @inject ( "TaskQueue" ) private readonly queueImpl : TaskQueue
31
- ) { }
32
-
33
- public registerListener (
34
- flowId : string ,
35
- queue : string ,
36
- listener : ( payload : TaskPayload ) => Promise < void >
37
- ) {
38
- if ( this . listeners [ queue ] === undefined ) {
39
- this . listeners [ queue ] = { } ;
40
- }
41
- this . listeners [ queue ] [ flowId ] = listener ;
42
- }
43
-
44
- public unregisterListener ( flowId : string , queue : string ) {
45
- delete this . listeners [ queue ] [ flowId ] ;
46
- }
47
-
48
- private async openQueue ( name : string ) : Promise < InstantiatedQueue > {
49
- const queue = await this . queueImpl . getQueue ( name ) ;
50
- await queue . onCompleted ( async ( payload ) => {
51
- await this . onCompleted ( name , payload ) ;
52
- } ) ;
53
- return queue ;
54
- }
55
-
56
- private async onCompleted ( name : string , payload : TaskPayload ) {
57
- const listener = this . listeners [ name ] ?. [ payload . flowId ] ;
58
- if ( listener !== undefined ) {
59
- await listener ( payload ) ;
60
- }
61
- }
62
-
63
- public async getQueue ( name : string ) {
64
- if ( this . queues [ name ] !== undefined ) {
65
- return this . queues [ name ] ;
66
- }
67
- const queue = await this . openQueue ( name ) ;
68
- this . queues [ name ] = queue ;
69
- return queue ;
70
- }
71
-
72
- async close ( ) {
73
- // TODO
74
- }
75
- }
76
-
77
15
interface CompletedCallback < Input , Result > {
78
16
( result : Result , originalInput : Input ) : Promise < any > ;
79
17
}
@@ -83,7 +21,10 @@ export class Flow<State> implements Closeable {
83
21
// therefore cancelled
84
22
private erroredOut = false ;
85
23
86
- private readonly registeredListeners : string [ ] = [ ] ;
24
+ private readonly registeredListeners : {
25
+ queueName : string ;
26
+ listenerId : number ;
27
+ } [ ] = [ ] ;
87
28
88
29
private resultsPending : {
89
30
[ key : string ] : ( payload : TaskPayload ) => Promise < void > ;
@@ -98,28 +39,28 @@ export class Flow<State> implements Closeable {
98
39
public tasksInProgress = 0 ;
99
40
100
41
public constructor (
101
- private readonly connectionHolder : ConnectionHolder ,
42
+ private readonly queueImpl : TaskQueue ,
102
43
public readonly flowId : string ,
103
44
public state : State
104
45
) { }
105
46
106
- private waitForResult (
107
- queue : string ,
47
+ private async waitForResult (
48
+ queue : InstantiatedQueue ,
108
49
taskId : string ,
109
50
callback : ( payload : TaskPayload ) => Promise < void >
110
51
) {
111
52
this . resultsPending [ taskId ] = callback ;
112
53
113
- if ( ! this . registeredListeners . includes ( queue ) ) {
114
- // Open Listener onto Connectionhandler
115
- this . connectionHolder . registerListener (
116
- this . flowId ,
117
- queue ,
118
- async ( payload ) => {
54
+ if ( ! this . registeredListeners . find ( ( l ) => l . queueName === queue . name ) ) {
55
+ const listenerId = await queue . onCompleted ( async ( payload ) => {
56
+ if ( payload . flowId === this . flowId ) {
119
57
await this . resolveResponse ( payload ) ;
120
58
}
121
- ) ;
122
- this . registeredListeners . push ( queue ) ;
59
+ } ) ;
60
+ this . registeredListeners . push ( {
61
+ queueName : queue . name ,
62
+ listenerId,
63
+ } ) ;
123
64
}
124
65
}
125
66
@@ -167,7 +108,7 @@ export class Flow<State> implements Closeable {
167
108
) : Promise < void > {
168
109
const queueName = task . name ;
169
110
const taskName = overrides ?. taskName ?? task . name ;
170
- const queue = await this . connectionHolder . getQueue ( queueName ) ;
111
+ const queue = await this . queueImpl . getQueue ( queueName ) ;
171
112
172
113
const payload = await task . inputSerializer ( ) . toJSON ( input ) ;
173
114
@@ -197,7 +138,7 @@ export class Flow<State> implements Closeable {
197
138
this . tasksInProgress -= 1 ;
198
139
return await completed ?.( decoded , input ) ;
199
140
} ;
200
- this . waitForResult ( queueName , taskId , callback ) ;
141
+ await this . waitForResult ( queue , taskId , callback ) ;
201
142
}
202
143
203
144
public async forEach < Type > (
@@ -222,17 +163,23 @@ export class Flow<State> implements Closeable {
222
163
}
223
164
224
165
public async close ( ) {
225
- this . registeredListeners . forEach ( ( queue ) => {
226
- this . connectionHolder . unregisterListener ( this . flowId , queue ) ;
227
- } ) ;
166
+ await mapSequential (
167
+ this . registeredListeners ,
168
+ async ( { queueName, listenerId } ) => {
169
+ const queue = await this . queueImpl . getQueue ( queueName ) ;
170
+ queue . offCompleted ( listenerId ) ;
171
+ }
172
+ ) ;
228
173
}
229
174
}
230
175
231
176
@injectable ( )
232
177
export class FlowCreator {
233
- public constructor ( private readonly connectionHolder : ConnectionHolder ) { }
178
+ public constructor (
179
+ @inject ( "TaskQueue" ) private readonly queueImpl : TaskQueue
180
+ ) { }
234
181
235
182
public createFlow < State > ( flowId : string , state : State ) : Flow < State > {
236
- return new Flow ( this . connectionHolder , flowId , state ) ;
183
+ return new Flow ( this . queueImpl , flowId , state ) ;
237
184
}
238
185
}
0 commit comments