async-conductor
Async Conductor - library that helps to orchestrate asynchronous application
components. Inspired by python library:
AIOConductor.
Usage
It can be a difficult task to set up and shutdown all application components such as
database, queue and so on in right order if we are talking about async
application.
How it can be solved by Async Conductor:
import { Conductor, Component } from "async-conductor";
interface Context {
[key: string]: string;
}
class AsyncLogger extends Component<Context> {
async onSetup(): Promise<void> {
}
async onShutdown(): Promise<void> {
}
info(): void {}
warn(): void {}
error(): void {}
}
class Database extends Component<Context> {
dependencies = [AsyncLogger];
async onSetup(): Promise<void> {
const logger = this.getDependency(AsyncLogger);
logger.info("Starting connection");
const host = this.context.host;
}
async onShutdown(): Promise<void> {
logger.info("Clisong connection");
}
async typicalDBMethod(): Promise<void> {
}
}
class API extends Component<Context> {
dependencies = [AsyncLogger, Database];
async onSetup(): Promise<void> {
const database = this.getDependency(Database);
await database.typicalDBMethod();
const logger = this.getDependency(AsyncLogger);
logger.info("Starting webServer...");
}
async onShutdown(): Promise<void> {
logger.info("Shutdown webServer...");
}
}
const apiConductor = new Conductor<Context>({"host": "localhost"});
apiConductor.add(API);
apiConductor.setup().then(() => {
const logger = apiConductor.get(AsyncLogger);
logger.info("Conductor estabileshed");
}).catch((error) => {
console.log("something goes wrong");
});
apiConductor.active.then(() => {
const logger = apiConductor.get(AsyncLogger);
logger.info("Conductor estabileshed");
});
apiConductor.inactive.then(() => {
const logger = apiConductor.get(AsyncLogger);
logger.info("condcutor is inactive");
});
process.on('exit', function () {
apiConductor.shutdown().catch((error) => {
console.log("something goes wrong");
}).finally(() => {
console.log("condcutor is inactive");
});
});
Conductor setup all your components in right order: if a component
has dependencies they are setup before the component.
This is the same for the shutdown process - all dependencies are teared down
before the main component.
Testing
Component can be patched for testing purposes. All other components depending on the original will use patched instance.
class Database extends Component {
dependencies = [AsyncLogger];
async onSetup(): Promise<void> {
const logger = this.getDependency(AsyncLogger);
logger.info("Starting connection");
const host = this.context.host;
}
async onShutdown(): Promise<void> {
logger.info("Clisong connection");
}
async typicalDBMethod(): Promise<void> {
}
}
class API extends Component {
dependencies = [Database];
async onSetup(): Promise<void> {
const database = this.getDependency(Database);
await database.typicalDBMethod();
const logger = this.getDependency(AsyncLogger);
logger.info("Starting webServer...");
}
async onShutdown(): Promise<void> {
logger.info("Shutdown webServer...");
}
}
class MockDatabase extends Database {
dependencies = [AsyncLogger];
async onSetup(): Promise<void> {
}
async onShutdown(): Promise<void> {
}
async typicalDBMethod(): Promise<void> {
}
}
const apiConductor = new Conductor();
apiConductor.add(API);
apiConductor.patch(Database, MockDatabase);
apiConductor.setup().then(() => {
const mockDB = apiConductor.get(Database);
logger.info("Conductor estabileshed");
}).catch((error) => {
console.log("something goes wrong");
});