diff --git a/packages/node/bin/streamr-node.ts b/packages/node/bin/streamr-node.ts index 2d536d6f9b..8a560cbc50 100644 --- a/packages/node/bin/streamr-node.ts +++ b/packages/node/bin/streamr-node.ts @@ -1,11 +1,13 @@ #!/usr/bin/env node import { program } from 'commander' import pkg from '../package.json' - +import { Logger } from '@streamr/utils' import { createBroker } from '../src/broker' import { readConfigAndMigrateIfNeeded } from '../src/config/migration' import { overrideConfigToEnvVarsIfGiven } from '../src/config/config' +const logger = new Logger(module) + program .version(pkg.version) .name('streamr-node') @@ -17,6 +19,28 @@ program const config = readConfigAndMigrateIfNeeded(configFile) overrideConfigToEnvVarsIfGiven(config) const broker = await createBroker(config) + + // Set up graceful shutdown handlers + const shutdown = async (exitCode: number) => { + await broker.stop() + process.exit(exitCode) + } + + const exitEvents = ['SIGINT', 'SIGTERM', 'SIGUSR1', 'SIGUSR2'] + exitEvents.forEach((event) => { + process.on(event, () => shutdown(0)) + }) + + process.on('uncaughtException', (err) => { + logger.fatal('Encountered uncaughtException', { err }) + shutdown(1) + }) + + process.on('unhandledRejection', (err) => { + logger.fatal('Encountered unhandledRejection', { err }) + shutdown(1) + }) + if (!program.opts().test) { await broker.start() } else { diff --git a/packages/node/src/broker.ts b/packages/node/src/broker.ts index 9f236d9f9e..01ddf54e53 100644 --- a/packages/node/src/broker.ts +++ b/packages/node/src/broker.ts @@ -78,13 +78,3 @@ export const createBroker = async (configWithoutDefaults: Config): Promise { - logger.fatal('Encountered uncaughtException', { err }) - process.exit(1) -}) - -process.on('unhandledRejection', (err) => { - logger.fatal('Encountered unhandledRejection', { err }) - process.exit(1) -}) diff --git a/packages/sdk/README.md b/packages/sdk/README.md index 4e13c84e0a..4314431c9d 100644 --- a/packages/sdk/README.md +++ b/packages/sdk/README.md @@ -118,6 +118,13 @@ streamr.resend(streamId, { last: 10 }, (msgs) => { }); ``` +### Clean up +After the StreamrClient is no longer used or the process is shutting down it is very important to call `destroy` on the StreamrClient. This ensures that the network node of the client will be shutdown gracefully. + +```js +await streamr.destroy() +``` + ___ **This Readme only scratches the surface of what's possible - be sure to [checkout our documentation](https://docs.streamr.network) for the full usage instructions.** diff --git a/packages/trackerless-network/src/NetworkStack.ts b/packages/trackerless-network/src/NetworkStack.ts index e9924005b2..84729f029e 100644 --- a/packages/trackerless-network/src/NetworkStack.ts +++ b/packages/trackerless-network/src/NetworkStack.ts @@ -8,7 +8,6 @@ import { toNodeId } from '@streamr/dht' import { Logger, MetricsContext, StreamID, StreamPartID, toStreamPartID, until } from '@streamr/utils' -import pull from 'lodash/pull' import { version as applicationVersion } from '../package.json' import { ContentDeliveryManager, ContentDeliveryManagerOptions, StreamPartDeliveryOptions } from './ContentDeliveryManager' import { ControlLayerNode } from './control-layer/ControlLayerNode' @@ -25,31 +24,6 @@ export interface NetworkOptions { const logger = new Logger(module) -const instances: NetworkStack[] = [] -const stopInstances = async () => { - // make a clone so that it is ok for each instance.stop() to remove itself from the list (at line 139) - // while the map function is iterating the list - const clonedInstances = [...instances] - await Promise.all(clonedInstances.map((instance) => instance.stop())) -} -const EXIT_EVENTS = [`exit`, `SIGINT`, `SIGUSR1`, `SIGUSR2`, `uncaughtException`, `unhandledRejection`, `SIGTERM`] -EXIT_EVENTS.forEach((event) => { - process.on(event, async (eventArg) => { - const isError = (event === 'uncaughtException') || (event === 'unhandledRejection') - if (isError) { - logger.error(`exit event: ${event}`, eventArg) - } - await stopInstances() - process.exit(isError ? 1 : 0) - }) -}) -declare let window: any -if (typeof window === 'object') { - window.addEventListener('unload', async () => { - await stopInstances() - }) -} - export class NetworkStack { private controlLayerNode?: ControlLayerNode @@ -72,7 +46,6 @@ export class NetworkStack { ...options.networkNode, metricsContext: this.metricsContext }) - instances.push(this) } async joinStreamPart( @@ -190,7 +163,6 @@ export class NetworkStack { async stop(): Promise { if (!this.stopped) { this.stopped = true - pull(instances, this) await this.contentDeliveryManager!.destroy() await this.controlLayerNode!.stop() this.contentDeliveryManager = undefined