@@ -66,6 +66,14 @@ export class Sequencer<Modules extends SequencerModulesRecord>
66
66
* modules to start each
67
67
*/
68
68
public async start ( ) {
69
+ // The sequencer uses tsyringe to resolve modules (and their dependencies)
70
+ // and then starts them. However, this can be problematic as although tsyringe may resolve
71
+ // dependencies, it doesn't actually start them. For example, a database may be created,
72
+ // but the connection strings, etc, won't be constructed until it's started, and this may
73
+ // cause an error if a module that relies on it is started first. The way to fix this is
74
+ // ensure that we start modules based on the order they were resolved.
75
+ // We iterate through the methods three times:
76
+
69
77
this . useDependencyFactory ( this . container . resolve ( MethodIdFactory ) ) ;
70
78
71
79
// Log startup info
@@ -75,15 +83,41 @@ export class Sequencer<Modules extends SequencerModulesRecord>
75
83
log . info ( "Starting sequencer..." ) ;
76
84
log . info ( "Modules:" , moduleClassNames ) ;
77
85
86
+ // Iteration #1: We invoke the afterResolution feature for the container
87
+ // to ensure every time a module is resolved it gets recorded.
88
+ const orderedModules : Extract < keyof Modules , string > [ ] = [ ] ;
89
+ // eslint-disable-next-line guard-for-in
90
+ for ( const moduleName in this . definition . modules ) {
91
+ this . container . afterResolution (
92
+ moduleName ,
93
+ ( ) => {
94
+ orderedModules . push ( moduleName ) ;
95
+ } ,
96
+ {
97
+ frequency : "Once" ,
98
+ }
99
+ ) ;
100
+ }
101
+ // Iteration #2: We resolve each module and thus populate
102
+ // the orderedModules list to understand the sequencing.
78
103
// eslint-disable-next-line guard-for-in
79
104
for ( const moduleName in this . definition . modules ) {
80
105
const sequencerModule = this . resolve ( moduleName ) ;
81
-
82
106
log . info (
83
- `Starting sequencer module ${ moduleName } (${ sequencerModule . constructor . name } )`
107
+ `Resolving sequencer module ${ moduleName } (${ sequencerModule . constructor . name } )`
84
108
) ;
109
+ }
110
+
111
+ // Iteration #3: We now iterate though the orderedModules list
112
+ // and start the modules in the order they were resolved.
113
+ for ( const moduleName of orderedModules ) {
114
+ const sequencerModule = this . resolve ( moduleName ) ;
85
115
// eslint-disable-next-line no-await-in-loop
86
116
await sequencerModule . start ( ) ;
117
+
118
+ log . info (
119
+ `Starting sequencer module ${ moduleName } (${ sequencerModule . constructor . name } )`
120
+ ) ;
87
121
}
88
122
}
89
123
}
0 commit comments