diff --git a/packages/api/src/graphql/GraphqlSequencerModule.ts b/packages/api/src/graphql/GraphqlSequencerModule.ts index adb0c4e2c..711394a42 100644 --- a/packages/api/src/graphql/GraphqlSequencerModule.ts +++ b/packages/api/src/graphql/GraphqlSequencerModule.ts @@ -8,6 +8,7 @@ import { ModuleContainer, ModulesConfig, ModulesRecord, + noop, TypedClass, } from "@proto-kit/common"; @@ -74,4 +75,8 @@ export class GraphqlSequencerModule } void this.graphqlServer.startServer(); } + + public async close(): Promise { + noop(); + } } diff --git a/packages/sdk/src/appChain/AppChain.ts b/packages/sdk/src/appChain/AppChain.ts index f14697a11..fb436efdd 100644 --- a/packages/sdk/src/appChain/AppChain.ts +++ b/packages/sdk/src/appChain/AppChain.ts @@ -352,4 +352,8 @@ export class AppChain< // this.runtime.start(); await this.sequencer.start(); } + + public async close(): Promise { + await this.sequencer.close(); + } } diff --git a/packages/sdk/test/graphql/run-graphql.test.ts b/packages/sdk/test/graphql/run-graphql.test.ts index 822625889..3d154ec36 100644 --- a/packages/sdk/test/graphql/run-graphql.test.ts +++ b/packages/sdk/test/graphql/run-graphql.test.ts @@ -1,9 +1,18 @@ -import { startServer } from "./graphql"; import { sleep } from "@proto-kit/common"; +import { AppChain } from "../../src"; + +import { startServer } from "./graphql"; + describe("run graphql", () => { + let appchain: AppChain; + + afterAll(async () => { + await appchain.close(); + }); + it("run", async () => { - const server = await startServer(); + appchain = await startServer(); await sleep(1000000000); }, 1000000000); }); diff --git a/packages/sequencer/src/sequencer/builder/SequencerModule.ts b/packages/sequencer/src/sequencer/builder/SequencerModule.ts index d15209ef1..ebc81ce9a 100644 --- a/packages/sequencer/src/sequencer/builder/SequencerModule.ts +++ b/packages/sequencer/src/sequencer/builder/SequencerModule.ts @@ -4,7 +4,7 @@ import { StaticConfigurableModule, TypedClass, Presets, - NoConfig, + NoConfig, noop } from "@proto-kit/common"; import { injectable } from "tsyringe"; @@ -24,6 +24,15 @@ export abstract class SequencerModule< * That means that you mustn't await server.start() for example. */ public abstract start(): Promise; + + /** + * Close() is called by the sequencer when the appchain or the sequencer + * is in the process of stopping. + * Possible usages are stopping of API services, closing of database connections, ... + */ + public async close(): Promise { + noop(); + } } /** diff --git a/packages/sequencer/src/sequencer/executor/Sequencer.ts b/packages/sequencer/src/sequencer/executor/Sequencer.ts index 609f7f172..499e988d7 100644 --- a/packages/sequencer/src/sequencer/executor/Sequencer.ts +++ b/packages/sequencer/src/sequencer/executor/Sequencer.ts @@ -6,7 +6,11 @@ import { ModuleContainerDefinition, log, } from "@proto-kit/common"; -import { Runtime, RuntimeModulesRecord, MethodIdFactory } from "@proto-kit/module"; +import { + Runtime, + RuntimeModulesRecord, + MethodIdFactory, +} from "@proto-kit/module"; import { Protocol, ProtocolModulesRecord } from "@proto-kit/protocol"; import { DependencyContainer, injectable } from "tsyringe"; @@ -87,4 +91,23 @@ export class Sequencer await sequencerModule.start(); } } + + public async close(): Promise { + let counter = 0; + + const { modules } = this.definition; + const totalModules = Object.keys(modules).length; + + for (const moduleName in modules) { + const sequencerModule = this.resolve(moduleName); + + log.info( + `Closing sequencer module ${moduleName} (${ + sequencerModule.constructor.name + }) ${++counter}/${totalModules}` + ); + // eslint-disable-next-line no-await-in-loop + await sequencerModule.close(); + } + } }