@@ -66,6 +66,14 @@ export class Sequencer<Modules extends SequencerModulesRecord>
6666 * modules to start each
6767 */
6868 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+
6977 this . useDependencyFactory ( this . container . resolve ( MethodIdFactory ) ) ;
7078
7179 // Log startup info
@@ -75,15 +83,41 @@ export class Sequencer<Modules extends SequencerModulesRecord>
7583 log . info ( "Starting sequencer..." ) ;
7684 log . info ( "Modules:" , moduleClassNames ) ;
7785
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.
78103 // eslint-disable-next-line guard-for-in
79104 for ( const moduleName in this . definition . modules ) {
80105 const sequencerModule = this . resolve ( moduleName ) ;
81-
82106 log . info (
83- `Starting sequencer module ${ moduleName } (${ sequencerModule . constructor . name } )`
107+ `Resolving sequencer module ${ moduleName } (${ sequencerModule . constructor . name } )`
84108 ) ;
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 ) ;
85115 // eslint-disable-next-line no-await-in-loop
86116 await sequencerModule . start ( ) ;
117+
118+ log . info (
119+ `Starting sequencer module ${ moduleName } (${ sequencerModule . constructor . name } )`
120+ ) ;
87121 }
88122 }
89123}
0 commit comments