Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 36 additions & 2 deletions packages/sequencer/src/sequencer/executor/Sequencer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ export class Sequencer<Modules extends SequencerModulesRecord>
* modules to start each
*/
public async start() {
// The sequencer uses tsyringe to resolve modules (and their dependencies)
// and then starts them. However, this can be problematic as although tsyringe may resolve
// dependencies, it doesn't actually start them. For example, a database may be created,
// but the connection strings, etc, won't be constructed until it's started, and this may
// cause an error if a module that relies on it is started first. The way to fix this is
// ensure that we start modules based on the order they were resolved.
// We iterate through the methods three times:

this.useDependencyFactory(this.container.resolve(MethodIdFactory));

// Log startup info
Expand All @@ -75,15 +83,41 @@ export class Sequencer<Modules extends SequencerModulesRecord>
log.info("Starting sequencer...");
log.info("Modules:", moduleClassNames);

// Iteration #1: We invoke the afterResolution feature for the container
// to ensure every time a module is resolved it gets recorded.
const orderedModules: Extract<keyof Modules, string>[] = [];
// eslint-disable-next-line guard-for-in
for (const moduleName in this.definition.modules) {
this.container.afterResolution(
moduleName,
() => {
orderedModules.push(moduleName);
},
{
frequency: "Once",
}
);
}
// Iteration #2: We resolve each module and thus populate
// the orderedModules list to understand the sequencing.
// eslint-disable-next-line guard-for-in
for (const moduleName in this.definition.modules) {
const sequencerModule = this.resolve(moduleName);

log.info(
`Starting sequencer module ${moduleName} (${sequencerModule.constructor.name})`
`Resolving sequencer module ${moduleName} (${sequencerModule.constructor.name})`
);
}

// Iteration #3: We now iterate though the orderedModules list
// and start the modules in the order they were resolved.
for (const moduleName of orderedModules) {
const sequencerModule = this.resolve(moduleName);
// eslint-disable-next-line no-await-in-loop
await sequencerModule.start();

log.info(
`Starting sequencer module ${moduleName} (${sequencerModule.constructor.name})`
);
}
}
}
Loading