1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
import {
Either,
IEither,
IMetric,
ITraceable,
LogMetricTrace,
LogMetricTraceSupplier,
Mapper,
Metric,
Optional,
ResultMetric,
SideEffect,
TraceUtil,
} from '@emprespresso/pengueno';
export const SigIntMetric = Metric.fromName('SigInt').asResult();
export const SigTermMetric = Metric.fromName('SigTerm').asResult();
export interface Closeable<TFailure> {
readonly close: SideEffect<SideEffect<TFailure | undefined>>;
}
export class Signals {
public static async awaitClose<E extends Error>(
t: ITraceable<Closeable<E>, LogMetricTraceSupplier>,
): Promise<IEither<Error, void>> {
const success: IEither<Error, void> = Either.right(<void>undefined);
return new Promise<IEither<Error, void>>((res) => {
const metricizedInterruptHandler = (metric: ResultMetric) => (err: Error | undefined) =>
t
.flatMap(TraceUtil.withMetricTrace(metric))
.peek((_t) => _t.trace.trace('closing'))
.move(
Optional.from(err)
.map((e) => Either.left<Error, void>(e))
.orSome(() => success)
.get(),
)
.flatMap(TraceUtil.traceResultingEither(metric))
.map((e) => res(e.get()))
.peek((_t) => _t.trace.trace('finished'))
.get();
const sigintCloser = metricizedInterruptHandler(SigIntMetric);
const sigtermCloser = metricizedInterruptHandler(SigTermMetric);
process.on('SIGINT', () => t.flatMap(TraceUtil.withTrace('SIGINT')).get().close(sigintCloser));
process.on('SIGTERM', () => t.flatMap(TraceUtil.withTrace('SIGTERM')).get().close(sigtermCloser));
});
}
}
|