-
Notifications
You must be signed in to change notification settings - Fork 13
/
api-core.ts
96 lines (86 loc) · 2.93 KB
/
api-core.ts
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import Core from './core';
import {
ExecutionConfig,
WorkerOperationLifeCycle,
SlicerOperationLifeCycle,
WorkerContext,
APIConfig,
DeadLetterAction,
DeadLetterAPIFn
} from '../../interfaces';
import { makeExContextLogger } from '../../utils';
/**
* A base class for supporting APIs that run within an Execution Context.
*/
export default abstract class APICore<T = APIConfig>
extends Core<WorkerContext>
implements WorkerOperationLifeCycle, SlicerOperationLifeCycle {
// ...
readonly apiConfig: Readonly<APIConfig & T>;
deadLetterAction: DeadLetterAction;
constructor(
context: WorkerContext,
apiConfig: APIConfig & T,
executionConfig: ExecutionConfig
) {
const logger = makeExContextLogger(context, executionConfig, 'operation-api', {
apiName: apiConfig._name,
});
super(context, executionConfig, logger);
this.apiConfig = apiConfig;
this.deadLetterAction = apiConfig._dead_letter_action || 'throw';
}
async initialize(): Promise<void> {
this.context.logger.trace(`${this.apiConfig._name}->api is initializing...`);
}
async shutdown(): Promise<void> {
this.context.logger.trace(`${this.apiConfig._name}->api is shutting down...`);
}
/**
* Try catch a transformation on a record and place any failed records in a dead letter queue
*
* See {@link #rejectRecord} for handling
*
* @param fn a function to transform the data with
* @returns a curried a function that will be called
* with the data and handle the dead letter action
*/
tryRecord<I, R>(fn: (input: I) => R): (input: I) => R | null {
return (input) => {
try {
return fn(input);
} catch (err) {
this.rejectRecord(input, err);
return null;
}
};
}
/**
* Reject a record using the dead letter action
*
* Based on {@link OpConfig._dead_letter_action} the transformation can
* be handled any of the following ways:
* - "throw": throw the original error
* - "log": log the error and the data
* - "none": skip the error entirely
* OR a string to specify the api to use as the dead letter queue
*
* @param data the data to transform
* @param fn a function to transform the data with
* @returns null
*/
rejectRecord(input: unknown, err: Error): never | null {
if (this.deadLetterAction === 'throw' || !this.deadLetterAction) {
throw err;
}
if (this.deadLetterAction === 'none') return null;
if (this.deadLetterAction === 'log') {
this.logger.error(err, 'Bad record', input);
return null;
}
const api = this.context.apis
.executionContext.getAPI(this.deadLetterAction) as DeadLetterAPIFn;
api(input, err);
return null;
}
}