@@ -19,26 +19,26 @@ export interface Cache<T, G> {
19
19
get ( ...args : any [ ] ) : Promise < T >
20
20
}
21
21
22
- type Task = [ string , Date , number ]
23
-
24
- function timeout ( ms : number ) {
25
- return new Promise ( ( resolve ) => setTimeout ( resolve , ms ) )
22
+ interface Task {
23
+ name : string
26
24
}
27
25
28
26
export function locked < T , G extends Actor > (
29
27
f : ( this : G , ...args : any [ ] ) => Promise < T | Error >
30
28
) : ( this : G , ...args : any [ ] ) => Promise < T | Error > {
31
29
return async function ( this : G , ...args : any [ ] ) : Promise < T | Error > {
32
30
// we lock the task
33
- if ( ( await this . lock ( f . name ) ) === false )
34
- return { status : Status . Failed } // we can't obtain a lock
35
-
36
- const result = await f . apply ( this , args )
37
-
38
- // we unlock the task
39
- this . unlock ( f . name )
40
-
41
- return result
31
+ const [ task , existing ] = this . lock ( f . name )
32
+ if ( existing ) return { status : Status . Failed } // we can't obtain a lock
33
+ try {
34
+ return await f . apply ( this , args )
35
+ } catch ( e ) {
36
+ console . log ( e )
37
+ return { status : Status . Failed }
38
+ } finally {
39
+ // we unlock the task
40
+ this . unlock ( f . name )
41
+ }
42
42
}
43
43
}
44
44
@@ -94,19 +94,15 @@ export class Actor extends Observer {
94
94
public actor : string
95
95
public id : string
96
96
97
- private _taskId : number
98
- private _tasks : Task [ ]
99
- private _locked : boolean
97
+ private _tasks : { [ Key : string ] : Task }
100
98
101
99
constructor ( actor : string , id : string , backend : Backend ) {
102
100
// the ID will be used to address local storage so that e.g. we can
103
101
// manage multiple providers, users etc. if necessary...
104
102
105
103
super ( )
106
104
107
- this . _taskId = 0
108
- this . _tasks = [ ]
109
- this . _locked = false
105
+ this . _tasks = { }
110
106
111
107
this . actor = actor
112
108
this . id = id
@@ -132,36 +128,21 @@ export class Actor extends Observer {
132
128
}
133
129
134
130
unlock ( task : string ) {
135
- if ( this . _tasks . length === 0 ) return false // should never happen
136
- if ( this . _tasks [ 0 ] [ 0 ] !== task ) return false // wrong task order (should not happen)
137
- this . _tasks = this . _tasks . slice ( 1 )
138
- return true
131
+ delete this . _tasks [ task ]
139
132
}
140
133
141
- async lock ( task : string ) {
142
- if ( this . _tasks . find ( ( t : Task ) => t [ 0 ] === task ) ! == undefined ) {
143
- console . warn (
144
- `Task ${ this . actor } :: ${ this . id } :: ${ task } is already in queue, aborting...`
145
- )
146
- return false
134
+ lock ( task : string ) : [ Task , boolean ] {
135
+ if ( this . _tasks [ task ] === undefined ) {
136
+ this . _tasks [ task ] = {
137
+ name : task ,
138
+ }
139
+ return [ this . _tasks [ task ] , false ]
147
140
}
148
141
149
- const taskId = this . _taskId ++
150
- this . _tasks . push ( [ task , new Date ( ) , taskId ] )
151
-
152
- while ( true ) {
153
- if ( this . _tasks . length === 0 ) return false // should not happen
154
- const [ t , dt , id ] = this . _tasks [ 0 ]
155
- if ( id === taskId ) break // it's our turn
156
- if ( new Date ( ) . getTime ( ) - dt . getTime ( ) > 1000 * 10 )
157
- // tasks time out after 10 seconds
158
- this . _tasks = this . _tasks . slice ( 1 )
159
- await timeout ( 10 )
160
- }
161
- return true
142
+ return [ this . _tasks [ task ] , true ]
162
143
}
163
144
164
145
clearLocks ( ) {
165
- this . _tasks = [ ]
146
+ this . _tasks = { }
166
147
}
167
148
}
0 commit comments