Skip to content

Commit

Permalink
refactor: Code style
Browse files Browse the repository at this point in the history
  • Loading branch information
zenflow committed Mar 19, 2021
1 parent 3d10fea commit 8aa626a
Show file tree
Hide file tree
Showing 32 changed files with 765 additions and 816 deletions.
6 changes: 3 additions & 3 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module.exports = {
globals: {
'ts-jest': {
babelConfig: '.babelrc',
"ts-jest": {
babelConfig: ".babelrc",
},
},
}
};
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,7 @@
},
"homepage": "https://github.com/zenflow/composite-service#readme",
"prettier": {
"printWidth": 80,
"semi": false,
"singleQuote": true,
"printWidth": 100,
"trailingComma": "all"
}
}
20 changes: 10 additions & 10 deletions release.config.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
module.exports = {
debug: true,
plugins: [
'@semantic-release/commit-analyzer',
'@semantic-release/release-notes-generator',
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
[
'@semantic-release/changelog',
"@semantic-release/changelog",
{
changelogFile: 'CHANGELOG.md',
changelogTitle: '# Changelog',
changelogFile: "CHANGELOG.md",
changelogTitle: "# Changelog",
},
],
'@semantic-release/npm',
"@semantic-release/npm",
[
'@semantic-release/git',
"@semantic-release/git",
{
assets: ['package.json', 'CHANGELOG.md'],
assets: ["package.json", "CHANGELOG.md"],
},
],
'@semantic-release/github',
"@semantic-release/github",
],
}
};
114 changes: 53 additions & 61 deletions src/CompositeService.ts
Original file line number Diff line number Diff line change
@@ -1,120 +1,112 @@
import { formatWithOptions } from 'util'
import mergeStream from 'merge-stream'
import { Service } from './Service'
import { NormalizedCompositeServiceConfig } from './validateAndNormalizeConfig'
import { Logger } from './Logger'
import { mapStreamLines } from './util/stream'
import { formatWithOptions } from "util";
import mergeStream from "merge-stream";
import { Service } from "./Service";
import { NormalizedCompositeServiceConfig } from "./validateAndNormalizeConfig";
import { Logger } from "./Logger";
import { mapStreamLines } from "./util/stream";

export class CompositeService {
private config: NormalizedCompositeServiceConfig
private services: Service[]
private serviceMap: Map<string, Service>
private stopping = false
private logger: Logger
private config: NormalizedCompositeServiceConfig;
private services: Service[];
private serviceMap: Map<string, Service>;
private stopping = false;
private logger: Logger;

constructor(config: NormalizedCompositeServiceConfig) {
this.config = config
this.config = config;

if (this.config.windowsCtrlCShutdown) {
require('generate-ctrl-c-event') // make sure this module loads before we even start
require("generate-ctrl-c-event"); // make sure this module loads before we even start
}

const outputStream = mergeStream()
outputStream.pipe(process.stdout)
const outputStream = mergeStream();
outputStream.pipe(process.stdout);

this.logger = new Logger(this.config.logLevel)
outputStream.add(this.logger.output)
this.logger = new Logger(this.config.logLevel);
outputStream.add(this.logger.output);

this.logger.log(
'debug',
formatWithOptions({ depth: null }, 'Config: %O', config),
)
this.logger.log("debug", formatWithOptions({ depth: null }, "Config: %O", config));

process.on('SIGINT', () => this.handleShutdownSignal(130, 'SIGINT'))
process.on('SIGTERM', () => this.handleShutdownSignal(143, 'SIGTERM'))
process.on("SIGINT", () => this.handleShutdownSignal(130, "SIGINT"));
process.on("SIGTERM", () => this.handleShutdownSignal(143, "SIGTERM"));
if (process.stdin.isTTY) {
process.stdin.setRawMode(true)
process.stdin.on('data', buffer => {
if (buffer.toString('utf8') === '\u0003') {
this.handleShutdownSignal(130, 'ctrl+c')
process.stdin.setRawMode(true);
process.stdin.on("data", buffer => {
if (buffer.toString("utf8") === "\u0003") {
this.handleShutdownSignal(130, "ctrl+c");
}
})
});
}

this.services = Object.entries(this.config.services).map(
([id, config]) =>
new Service(id, config, this.logger, this.handleFatalError.bind(this)),
)
this.serviceMap = new Map(
this.services.map(service => [service.id, service]),
)
([id, config]) => new Service(id, config, this.logger, this.handleFatalError.bind(this)),
);
this.serviceMap = new Map(this.services.map(service => [service.id, service]));

outputStream.add(
this.services.map(({ output, id }) =>
output.pipe(mapStreamLines(line => `${id} | ${line}\n`)),
),
)
);

this.logger.log('debug', 'Starting composite service...')
Promise.all(
this.services.map(service => this.startService(service)),
).then(() => this.logger.log('debug', 'Started composite service'))
this.logger.log("debug", "Starting composite service...");
Promise.all(this.services.map(service => this.startService(service))).then(() =>
this.logger.log("debug", "Started composite service"),
);
}

private async startService(service: Service) {
const dependencies = service.config.dependencies.map(
id => this.serviceMap.get(id)!,
)
await Promise.all(dependencies.map(service => this.startService(service)))
const dependencies = service.config.dependencies.map(id => this.serviceMap.get(id)!);
await Promise.all(dependencies.map(service => this.startService(service)));
if (this.stopping) {
await never()
await never();
}
await service.start()
await service.start();
if (this.stopping) {
await never()
await never();
}
}

private handleFatalError(message: string): void {
this.logger.log('error', `Fatal error: ${message}`)
this.logger.log("error", `Fatal error: ${message}`);
if (!this.stopping) {
this.stop(1)
this.stop(1);
}
}

private handleShutdownSignal(exitCode: number, description: string): void {
if (!this.stopping) {
this.logger.log('info', `Received shutdown signal (${description})`)
this.stop(exitCode)
this.logger.log("info", `Received shutdown signal (${description})`);
this.stop(exitCode);
}
}

private stop(exitCode: number): void {
if (this.stopping) return
this.stopping = true
this.logger.log('debug', 'Stopping composite service...')
if (this.stopping) return;
this.stopping = true;
this.logger.log("debug", "Stopping composite service...");
if (this.config.windowsCtrlCShutdown) {
require('generate-ctrl-c-event')
require("generate-ctrl-c-event")
.generateCtrlCAsync()
.catch((error: Error) => this.logger.log('error', String(error)))
.catch((error: Error) => this.logger.log("error", String(error)));
}
Promise.all(this.services.map(service => this.stopService(service)))
.then(() => this.logger.log('debug', 'Stopped composite service'))
.then(() => this.logger.log("debug", "Stopped composite service"))
// Wait one micro tick for output to flush
.then(() => process.exit(exitCode))
.then(() => process.exit(exitCode));
}

private async stopService(service: Service) {
if (this.config.gracefulShutdown) {
const dependents = this.services.filter(({ config }) =>
config.dependencies.includes(service.id),
)
await Promise.all(dependents.map(service => this.stopService(service)))
);
await Promise.all(dependents.map(service => this.stopService(service)));
}
await service.stop(this.config.windowsCtrlCShutdown)
await service.stop(this.config.windowsCtrlCShutdown);
}
}

function never(): Promise<never> {
return new Promise<never>(() => {})
return new Promise<never>(() => {});
}
8 changes: 4 additions & 4 deletions src/InternalError.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
const genericMessage =
'This is a bug in composite-service. Please file an issue in https://github.com/zenflow/composite-service/issues'
"This is a bug in composite-service. Please file an issue in https://github.com/zenflow/composite-service/issues";

export class InternalError extends Error {
constructor(message: string) {
super(`${message}. ${genericMessage}`)
Object.setPrototypeOf(this, InternalError.prototype)
super(`${message}. ${genericMessage}`);
Object.setPrototypeOf(this, InternalError.prototype);
}
}
InternalError.prototype.name = InternalError.name
InternalError.prototype.name = InternalError.name;
20 changes: 9 additions & 11 deletions src/Logger.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
import { PassThrough } from 'stream'
import { PassThrough } from "stream";

export type LogLevel = 'debug' | 'info' | 'error'
export type LogLevel = "debug" | "info" | "error";

const orderedLogLevels: LogLevel[] = ['error', 'info', 'debug']
const orderedLogLevels: LogLevel[] = ["error", "info", "debug"];

export class Logger {
private level: LogLevel
public readonly output = new PassThrough({ objectMode: true })
private level: LogLevel;
public readonly output = new PassThrough({ objectMode: true });
constructor(level: LogLevel) {
this.level = level
this.level = level;
}
public log(level: LogLevel, text: string) {
if (this.shouldLog(level)) {
for (const line of text.split('\n')) {
this.output.write(` (${level}) ${line}\n`)
for (const line of text.split("\n")) {
this.output.write(` (${level}) ${line}\n`);
}
}
}
private shouldLog(level: LogLevel) {
return (
orderedLogLevels.indexOf(level) <= orderedLogLevels.indexOf(this.level)
)
return orderedLogLevels.indexOf(level) <= orderedLogLevels.indexOf(this.level);
}
}
Loading

0 comments on commit 8aa626a

Please sign in to comment.