Skip to content

Commit 2d4e650

Browse files
committed
feat: lifecycle events for bot, svcs (#16)
1 parent 7955675 commit 2d4e650

File tree

6 files changed

+64
-15
lines changed

6 files changed

+64
-15
lines changed

src/BaseService.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import * as uuid from 'uuid/v4';
77

88
import { SchemaError } from 'src/error/SchemaError';
99
import { ServiceModule } from 'src/module/ServiceModule';
10-
import { Service, ServiceDefinition } from 'src/Service';
10+
import { Service, ServiceDefinition, ServiceLifecycle } from 'src/Service';
1111
import { Clock } from 'src/utils/Clock';
1212
import { JsonPath } from 'src/utils/JsonPath';
1313
import { dictToMap } from 'src/utils/Map';
@@ -64,6 +64,10 @@ export abstract class BaseService<TData> implements Service {
6464
}
6565
}
6666

67+
public async notify(event: ServiceLifecycle): Promise<void> {
68+
this.logger.debug({ event }, 'service notified of event');
69+
}
70+
6771
public abstract start(): Promise<void>;
6872
public abstract stop(): Promise<void>;
6973

src/Bot.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { checkFilter, Filter, FilterData, FilterValue } from 'src/filter/Filter'
1313
import { ContextFetchOptions, Listener, ListenerData } from 'src/listener/Listener';
1414
import { ServiceModule } from 'src/module/ServiceModule';
1515
import { Parser, ParserData } from 'src/parser/Parser';
16-
import { Service, ServiceDefinition } from 'src/Service';
16+
import { Service, ServiceDefinition, ServiceLifecycle } from 'src/Service';
1717
import { filterNil, mustFind } from 'src/utils';
1818
import { incrementServiceCounter } from 'src/utils/metrics/Service';
1919
import { StorageLogger, StorageLoggerOptions } from 'src/utils/StorageLogger';
@@ -88,6 +88,18 @@ export class Bot extends BaseService<BotData> implements Service {
8888
return this.storage;
8989
}
9090

91+
public async notify(event: ServiceLifecycle) {
92+
await super.notify(event);
93+
await this.services.notify(event);
94+
95+
switch (event) {
96+
case ServiceLifecycle.Reset:
97+
this.metrics.clear();
98+
this.logger.info('metrics reset');
99+
break;
100+
}
101+
}
102+
91103
/**
92104
* Set up the async resources that cannot be created in the constructor: filters, controllers, parsers, etc
93105
*/

src/Service.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ export interface ServiceDefinition<TData = any> {
88
data: TData;
99
}
1010

11+
export enum ServiceLifecycle {
12+
Reload = 'reload',
13+
Reset = 'reset',
14+
Start = 'start',
15+
Stop = 'stop',
16+
}
17+
1118
export interface ServiceMetadata {
1219
/**
1320
* The service's unique id.
@@ -33,6 +40,7 @@ export interface ServiceMetadata {
3340
export interface Service extends ServiceMetadata {
3441
readonly id: string;
3542

43+
notify(event: ServiceLifecycle): Promise<void>;
3644
start(): Promise<void>;
3745
stop(): Promise<void>;
3846
}

src/index.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Container, Module } from 'noicejs';
1+
import { Container, Logger, Module } from 'noicejs';
22
import * as sourceMapSupport from 'source-map-support';
33
import * as yargs from 'yargs-parser';
44

@@ -15,7 +15,8 @@ import { ServiceModule } from 'src/module/ServiceModule';
1515
import { TransformModule } from 'src/module/TransformModule';
1616
import { BunyanLogger } from 'src/utils/BunyanLogger';
1717
import { Schema } from 'src/utils/Schema';
18-
import { signal, SIGNAL_STOP } from 'src/utils/Signal';
18+
import { signal, SIGNAL_RELOAD, SIGNAL_RESET, SIGNAL_STOP } from 'src/utils/Signal';
19+
import { ServiceLifecycle } from './Service';
1920

2021
// main arguments
2122
const MAIN_ARGS: yargs.Options = {
@@ -81,9 +82,26 @@ function createModules(botModule: BotModule, migrate: boolean) {
8182
return modules;
8283
}
8384

84-
async function handleSignals(bot: Bot) {
85+
async function handleSignals(bot: Bot, logger: Logger) {
8586
await bot.start();
86-
await signal(SIGNAL_STOP);
87+
await bot.notify(ServiceLifecycle.Start);
88+
89+
const signals = [SIGNAL_RELOAD, SIGNAL_RESET, SIGNAL_STOP];
90+
let s = await signal(...signals);
91+
while (s !== SIGNAL_STOP) {
92+
switch (s) {
93+
case SIGNAL_RELOAD:
94+
bot.notify(ServiceLifecycle.Reload);
95+
break;
96+
case SIGNAL_RESET:
97+
bot.notify(ServiceLifecycle.Reset);
98+
break;
99+
}
100+
s = await signal(...signals);
101+
}
102+
103+
logger.info('stop signal');
104+
await bot.notify(ServiceLifecycle.Stop);
87105
await bot.stop();
88106
}
89107

@@ -116,7 +134,7 @@ async function main(argv: Array<string>): Promise<number> {
116134
botModule.setBot(bot);
117135

118136
logger.info('starting bot');
119-
await handleSignals(bot);
137+
await handleSignals(bot, logger);
120138

121139
return STATUS_SUCCESS;
122140
}

src/module/ServiceModule.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Container } from 'noicejs/Container';
44

55
import { BotServiceOptions } from 'src/BotService';
66
import { NotFoundError } from 'src/error/NotFoundError';
7-
import { Service, ServiceDefinition, ServiceMetadata } from 'src/Service';
7+
import { Service, ServiceDefinition, ServiceMetadata, ServiceLifecycle } from 'src/Service';
88
import { mustGet } from 'src/utils/Map';
99

1010
/**
@@ -29,6 +29,12 @@ export class ServiceModule extends Module implements Service {
2929
return this.services.size;
3030
}
3131

32+
public async notify(event: ServiceLifecycle) {
33+
for (const svc of this.services.values()) {
34+
await svc.notify(event);
35+
}
36+
}
37+
3238
public async start() {
3339
for (const svc of this.services.values()) {
3440
await svc.start();

src/utils/Signal.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
export const SIGNAL_RELOAD: Array<NodeJS.Signals> = ['SIGHUP'];
2-
export const SIGNAL_STOP: Array<NodeJS.Signals> = ['SIGINT', 'SIGTERM'];
1+
export const SIGNAL_RELOAD: NodeJS.Signals = 'SIGHUP';
2+
export const SIGNAL_RESET: NodeJS.Signals = 'SIGINT';
3+
export const SIGNAL_STOP: NodeJS.Signals = 'SIGTERM';
34

4-
export function signal(signals: Array<NodeJS.Signals>): Promise<void> {
5+
export function signal(...signals: Array<NodeJS.Signals>): Promise<NodeJS.Signals> {
56
return new Promise((res, _) => {
6-
function handler() {
7-
for (const sig of signals) {
8-
process.removeListener(sig, handler);
7+
function handler(fired: NodeJS.Signals) {
8+
for (const signal of signals) {
9+
process.removeListener(signal, handler);
910
}
10-
res();
11+
res(fired);
1112
}
1213

1314
for (const sig of signals) {

0 commit comments

Comments
 (0)