Skip to content

Commit 2d5ca04

Browse files
authored
Merge pull request #245 from proto-kit/fix/resolve-sequencer-ordering
Record resolving order in the sequencer and start modules based on that
2 parents 6225088 + ce40647 commit 2d5ca04

File tree

1 file changed

+36
-2
lines changed

1 file changed

+36
-2
lines changed

packages/sequencer/src/sequencer/executor/Sequencer.ts

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)