Skip to content

Commit

Permalink
fix: logger
Browse files Browse the repository at this point in the history
  • Loading branch information
izatop committed Nov 21, 2021
1 parent dfb8b99 commit 36b9df1
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 37 deletions.
1 change: 0 additions & 1 deletion packages/unit/src/Runtime/Heartbeat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ export class Heartbeat extends Disposer {

public static create(target: IRunnable): Heartbeat {
const heartbeat = registry.get(target) ?? new Heartbeat(target);

if (!registry.has(target)) {
// prevent the getHeartbeat() function to be called more than one time
Object.defineProperty(target, "getHeartbeat", {value: () => heartbeat});
Expand Down
53 changes: 30 additions & 23 deletions packages/unit/src/Runtime/Runtime.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Defer, isNull, isUndefined, Logger, logger, SingleRef} from "@bunt/util";
import {Defer, isNull, isUndefined, LogFn, Logger, logger, SingleRef} from "@bunt/util";
import {Disposer, dispose} from "../Dispose";
import {Heartbeat} from "./Heartbeat";
import {RuntimeTask} from "./interfaces";
Expand All @@ -13,7 +13,7 @@ export class Runtime extends Disposer {
public readonly logger!: Logger;

readonly #running: Heartbeat[] = [];
readonly #working: Promise<unknown>[] = [];
readonly #pending: Promise<unknown>[] = [];
readonly #state = new Defer<void>();

private readonly created: Date;
Expand All @@ -22,21 +22,30 @@ export class Runtime extends Disposer {
super();

this.created = new Date();
this.logger.info("register", {ENV, DEBUG});
this.logger.info("run", {ENV, DEBUG, date: this.created});

// @TODO Send an event when a signal has been received.
for (const signal of Signals) {
this.logger.debug("listen", signal);
process.on(signal, async () => Runtime.kill());
this.logger.debug("watch", signal);
process.on(signal, async () => Runtime.kill(0, `Signal ${signal} has been received`));
}

this.onDispose(Logger);
}

public static kill(code = 0, reason?: unknown): Promise<void> {
return ref
.ensure()
.kill(code, reason);
}

public static async kill(code = 0) {
const runtime = ref.ensure();
await Promise.allSettled(runtime.#working);
await dispose(runtime);
public async kill(code = 0, reason?: unknown) {
const fn: LogFn = code > 0 ? this.logger.error : this.logger.info;
fn("Kill { code: %d, reason: %s }", code, reason);

if (!this.isTest()) {
await Promise.allSettled(this.#pending);
await dispose(this);

if (!Runtime.isTest()) {
process.exit(code);
}
}
Expand All @@ -57,43 +66,41 @@ export class Runtime extends Disposer {
return ENV === "test";
}

public static run(...tasks: RuntimeTask[]): Runtime {
public static run(tasks: RuntimeTask[]): Runtime {
return ref
.once(() => new Runtime())
.run(tasks);
}

private run(tasks: RuntimeTask[]): this {
for (const task of tasks) {
try {
this.#working.push(Promise.resolve(task()));
} catch (error) {
this.#working.push(Promise.reject(error));
}
this.#pending.push(this.handle(task));
}

return this;
}

private async watch(): Promise<void> {
public async watch(): Promise<void> {
const finish = this.logger.perf("run");
try {
await Promise.allSettled(this.#working.map((job) => this.handle(job)));
await Promise.allSettled(this.#pending);
await Promise.all(this.#running.map((heartbeat) => heartbeat.watch()));
} catch (error) {
this.error(error);
} finally {
finish();
}

await dispose(this);
const code = this.#state.rejected ? 1 : 0;
const reason = this.#state.rejected ? "Some tasks were rejected" : "As expected";
await this.kill(code, reason);
}

private async handle(result: unknown): Promise<void> {
private async handle(task: RuntimeTask): Promise<void> {
try {
const object = await result;
this.logger.debug("handle", {object});
this.logger.debug("Run task");

const object = await task();
if (isUndefined(object) || isNull(object)) {
return;
}
Expand Down
10 changes: 5 additions & 5 deletions packages/unit/src/Runtime/internal.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {isObject, Logger, Promisify} from "@bunt/util";
import {isObject, Logger} from "@bunt/util";
import {RuntimeTask} from ".";
import {IDisposable, IRunnable} from "./interfaces";
import {Runtime} from "./Runtime";

Expand All @@ -12,10 +13,9 @@ export function isRunnable(target: unknown): target is IRunnable {
return isObject(target) && "getHeartbeat" in target;
}

export function main(...chain: (() => Promisify<unknown>)[]): void {
process.nextTick(async () => {
await Runtime.run(...chain);
});
export function main(...tasks: RuntimeTask[]): void {
Runtime.run(tasks)
.watch();
}

export const SystemLogger = new Logger("System");
6 changes: 3 additions & 3 deletions packages/unit/test/src/Runtime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import {RunnableTarget} from "./disposable/RunnableTarget";

describe("Runtime", () => {
test("dispose", async () => {
const runtime = Runtime.run(
const runtime = Runtime.run([
() => new RunnableTarget(),
() => new Target("runtime"),
);
]);

const pendingTest = expect(runtime.watch())
.resolves.not.toThrow();

await Runtime.kill();
await Runtime.kill(0, "Testing reason");

expect(disposedIds.has("runtime")).toBeTruthy();

Expand Down
16 changes: 12 additions & 4 deletions packages/util/src/Async/Defer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ export class Defer<T> implements PromiseLike<T> {
readonly #event = new EventEmitter();
readonly #pending: Promise<T>;

#settled = false;
#state: "rejected" | "fulfilled" | "pending" = "pending";

constructor() {
this.#event.once("resolve", () => this.#settled = true);
this.#event.once("reject", () => this.#settled = true);
this.#event.once("resolve", () => this.#state = "fulfilled");
this.#event.once("reject", () => this.#state = "rejected");

this.#pending = new Promise<T>((resolve, reject) => {
this.#event.once("resolve", resolve);
Expand All @@ -20,7 +20,15 @@ export class Defer<T> implements PromiseLike<T> {
}

public get settled() {
return this.#settled;
return this.#state !== "pending";
}

public get rejected() {
return this.settled && this.#state === "rejected";
}

public get fulfilled() {
return this.settled && this.#state === "fulfilled";
}

public then = <TResult1 = T, TResult2 = never>(onfulfilled?: DeferOnFulfilled<T, TResult1>,
Expand Down
2 changes: 1 addition & 1 deletion packages/util/src/Logger/Logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ export class Logger {
this.#label = label;
}

public async dispose(): Promise<void> {
public static async dispose(): Promise<void> {
writers.splice(0, writers.length);
await Promise.allSettled(transports.map((transport) => transport.close()));
}
Expand Down

0 comments on commit 36b9df1

Please sign in to comment.