@flink-app/flink 0.3.11 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/run.ts +23 -27
- package/dist/cli/run.js +1 -5
- package/dist/src/FlinkApp.d.ts +26 -2
- package/dist/src/FlinkApp.js +147 -36
- package/dist/src/FlinkJob.d.ts +58 -0
- package/dist/src/FlinkJob.js +2 -0
- package/dist/src/FlinkLog.d.ts +16 -0
- package/dist/src/FlinkLog.js +11 -30
- package/dist/src/TypeScriptCompiler.d.ts +5 -1
- package/dist/src/TypeScriptCompiler.js +61 -37
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.js +2 -1
- package/package.json +7 -3
- package/src/FlinkApp.ts +153 -8
- package/src/FlinkJob.ts +64 -0
- package/src/FlinkLog.ts +13 -11
- package/src/TypeScriptCompiler.ts +593 -663
- package/src/index.ts +2 -1
package/cli/run.ts
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import TypeScriptCompiler from "../src/TypeScriptCompiler";
|
|
3
3
|
|
|
4
4
|
module.exports = async function run(args: string[]) {
|
|
5
|
-
|
|
5
|
+
const startTime = Date.now();
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
if (args.includes("--help")) {
|
|
8
|
+
console.log(`
|
|
9
9
|
Description
|
|
10
10
|
Compiles and starts the application.
|
|
11
11
|
|
|
@@ -20,37 +20,33 @@ module.exports = async function run(args: string[]) {
|
|
|
20
20
|
--help Displays this message
|
|
21
21
|
`);
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
process.exit(0);
|
|
24
|
+
}
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
let dir = "./";
|
|
27
|
+
if (args[0] && !args[0].startsWith("--")) {
|
|
28
|
+
dir = args[0];
|
|
29
|
+
}
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
let entry = "/src/index.ts";
|
|
32
|
+
if (args.includes("--entry")) {
|
|
33
|
+
entry = args[args.indexOf("--entry") + 1];
|
|
34
|
+
entry = entry.startsWith("/") ? entry : "/" + entry;
|
|
35
|
+
}
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
await TypeScriptCompiler.clean(dir);
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
const compiler = new TypeScriptCompiler(dir);
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
if (!compiler.getPreEmitDiagnostics()) {
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
compiler.parseRepos(),
|
|
47
|
-
compiler.parseHandlers(),
|
|
48
|
-
compiler.generateStartScript(entry),
|
|
49
|
-
]);
|
|
45
|
+
await Promise.all([compiler.parseRepos(), compiler.parseHandlers(), compiler.parseJobs(), compiler.generateStartScript(entry)]);
|
|
50
46
|
|
|
51
|
-
|
|
47
|
+
console.log(`Compilation done, took ${Date.now() - startTime}ms`);
|
|
52
48
|
|
|
53
|
-
|
|
49
|
+
compiler.emit();
|
|
54
50
|
|
|
55
|
-
|
|
51
|
+
require("child_process").fork(dir + "/dist/.flink/start.js");
|
|
56
52
|
};
|
package/dist/cli/run.js
CHANGED
|
@@ -68,11 +68,7 @@ module.exports = function run(args) {
|
|
|
68
68
|
if (!compiler.getPreEmitDiagnostics()) {
|
|
69
69
|
process.exit(1);
|
|
70
70
|
}
|
|
71
|
-
return [4 /*yield*/, Promise.all([
|
|
72
|
-
compiler.parseRepos(),
|
|
73
|
-
compiler.parseHandlers(),
|
|
74
|
-
compiler.generateStartScript(entry),
|
|
75
|
-
])];
|
|
71
|
+
return [4 /*yield*/, Promise.all([compiler.parseRepos(), compiler.parseHandlers(), compiler.parseJobs(), compiler.generateStartScript(entry)])];
|
|
76
72
|
case 2:
|
|
77
73
|
_a.sent();
|
|
78
74
|
console.log("Compilation done, took ".concat(Date.now() - startTime, "ms"));
|
package/dist/src/FlinkApp.d.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
|
+
import { OptionsJson } from "body-parser";
|
|
1
2
|
import { Express } from "express";
|
|
2
3
|
import { JSONSchema7 } from "json-schema";
|
|
3
4
|
import { Db } from "mongodb";
|
|
5
|
+
import { ToadScheduler } from "toad-scheduler";
|
|
4
6
|
import { FlinkAuthPlugin } from "./auth/FlinkAuthPlugin";
|
|
5
7
|
import { FlinkContext } from "./FlinkContext";
|
|
6
8
|
import { HandlerFile, HttpMethod, QueryParamMetadata, RouteProps } from "./FlinkHttpHandler";
|
|
9
|
+
import { FlinkJobFile } from "./FlinkJob";
|
|
7
10
|
import { FlinkPlugin } from "./FlinkPlugin";
|
|
8
11
|
import { FlinkRepo } from "./FlinkRepo";
|
|
9
12
|
export type JSONSchema = JSONSchema7;
|
|
10
13
|
/**
|
|
11
14
|
* This will be populated at compile time when the apps handlers
|
|
12
|
-
* are picked up by
|
|
15
|
+
* are picked up by TypeScript compiler
|
|
13
16
|
*/
|
|
14
17
|
export declare const autoRegisteredHandlers: {
|
|
15
18
|
handler: HandlerFile;
|
|
@@ -17,13 +20,18 @@ export declare const autoRegisteredHandlers: {
|
|
|
17
20
|
}[];
|
|
18
21
|
/**
|
|
19
22
|
* This will be populated at compile time when the apps repos
|
|
20
|
-
* are picked up by
|
|
23
|
+
* are picked up by TypeScript compiler
|
|
21
24
|
*/
|
|
22
25
|
export declare const autoRegisteredRepos: {
|
|
23
26
|
collectionName: string;
|
|
24
27
|
repoInstanceName: string;
|
|
25
28
|
Repo: any;
|
|
26
29
|
}[];
|
|
30
|
+
/**
|
|
31
|
+
* This will be populated at compile time when the apps jobs
|
|
32
|
+
* are picked up by TypeScript compiler
|
|
33
|
+
*/
|
|
34
|
+
export declare const autoRegisteredJobs: FlinkJobFile[];
|
|
27
35
|
export interface FlinkOptions {
|
|
28
36
|
/**
|
|
29
37
|
* Name of application, will only show in logs and in HTTP header.
|
|
@@ -88,6 +96,17 @@ export interface FlinkOptions {
|
|
|
88
96
|
* Optional root folder of app. Defaults to `./`
|
|
89
97
|
*/
|
|
90
98
|
appRoot?: string;
|
|
99
|
+
/**
|
|
100
|
+
* Options for json body parser
|
|
101
|
+
*/
|
|
102
|
+
jsonOptions?: OptionsJson;
|
|
103
|
+
scheduling?: {
|
|
104
|
+
/**
|
|
105
|
+
* If true, the scheduler will be enabled.
|
|
106
|
+
* Defaults to true.
|
|
107
|
+
*/
|
|
108
|
+
enabled?: boolean;
|
|
109
|
+
};
|
|
91
110
|
}
|
|
92
111
|
export interface HandlerConfig {
|
|
93
112
|
schema?: {
|
|
@@ -124,11 +143,14 @@ export declare class FlinkApp<C extends FlinkContext> {
|
|
|
124
143
|
private auth?;
|
|
125
144
|
private corsOpts;
|
|
126
145
|
private routingConfigured;
|
|
146
|
+
private jsonOptions?;
|
|
147
|
+
private schedulingOptions?;
|
|
127
148
|
private repos;
|
|
128
149
|
/**
|
|
129
150
|
* Internal cache used to track registered handlers and potentially any overlapping routes
|
|
130
151
|
*/
|
|
131
152
|
private handlerRouteCache;
|
|
153
|
+
scheduler?: ToadScheduler;
|
|
132
154
|
constructor(opts: FlinkOptions);
|
|
133
155
|
get ctx(): C;
|
|
134
156
|
start(): Promise<this>;
|
|
@@ -147,6 +169,7 @@ export declare class FlinkApp<C extends FlinkContext> {
|
|
|
147
169
|
* Will not register any handlers added programmatically.
|
|
148
170
|
*/
|
|
149
171
|
private registerAutoRegisterableHandlers;
|
|
172
|
+
private registerAutoRegisterableJobs;
|
|
150
173
|
addRepo(instanceName: string, repoInstance: FlinkRepo<C>): void;
|
|
151
174
|
/**
|
|
152
175
|
* Constructs the app context. Will inject context in all components
|
|
@@ -163,4 +186,5 @@ export declare class FlinkApp<C extends FlinkContext> {
|
|
|
163
186
|
private initPluginDb;
|
|
164
187
|
private authenticate;
|
|
165
188
|
getRegisteredRoutes(): string[];
|
|
189
|
+
private get isSchedulingEnabled();
|
|
166
190
|
}
|
package/dist/src/FlinkApp.js
CHANGED
|
@@ -50,16 +50,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
50
50
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
51
51
|
};
|
|
52
52
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
53
|
-
exports.FlinkApp = exports.autoRegisteredRepos = exports.autoRegisteredHandlers = void 0;
|
|
53
|
+
exports.FlinkApp = exports.autoRegisteredJobs = exports.autoRegisteredRepos = exports.autoRegisteredHandlers = void 0;
|
|
54
54
|
var ajv_1 = __importDefault(require("ajv"));
|
|
55
55
|
var ajv_formats_1 = __importDefault(require("ajv-formats"));
|
|
56
56
|
var body_parser_1 = __importDefault(require("body-parser"));
|
|
57
57
|
var cors_1 = __importDefault(require("cors"));
|
|
58
58
|
var express_1 = __importDefault(require("express"));
|
|
59
59
|
var mongodb_1 = __importDefault(require("mongodb"));
|
|
60
|
-
var
|
|
60
|
+
var ms_1 = __importDefault(require("ms"));
|
|
61
|
+
var toad_scheduler_1 = require("toad-scheduler");
|
|
61
62
|
var uuid_1 = require("uuid");
|
|
62
63
|
var FlinkErrors_1 = require("./FlinkErrors");
|
|
64
|
+
var FlinkLog_1 = require("./FlinkLog");
|
|
63
65
|
var mock_data_generator_1 = __importDefault(require("./mock-data-generator"));
|
|
64
66
|
var utils_1 = require("./utils");
|
|
65
67
|
var ajv = new ajv_1.default();
|
|
@@ -71,14 +73,19 @@ var defaultCorsOptions = {
|
|
|
71
73
|
};
|
|
72
74
|
/**
|
|
73
75
|
* This will be populated at compile time when the apps handlers
|
|
74
|
-
* are picked up by
|
|
76
|
+
* are picked up by TypeScript compiler
|
|
75
77
|
*/
|
|
76
78
|
exports.autoRegisteredHandlers = [];
|
|
77
79
|
/**
|
|
78
80
|
* This will be populated at compile time when the apps repos
|
|
79
|
-
* are picked up by
|
|
81
|
+
* are picked up by TypeScript compiler
|
|
80
82
|
*/
|
|
81
83
|
exports.autoRegisteredRepos = [];
|
|
84
|
+
/**
|
|
85
|
+
* This will be populated at compile time when the apps jobs
|
|
86
|
+
* are picked up by TypeScript compiler
|
|
87
|
+
*/
|
|
88
|
+
exports.autoRegisteredJobs = [];
|
|
82
89
|
var FlinkApp = /** @class */ (function () {
|
|
83
90
|
function FlinkApp(opts) {
|
|
84
91
|
this.handlers = [];
|
|
@@ -99,6 +106,8 @@ var FlinkApp = /** @class */ (function () {
|
|
|
99
106
|
this.plugins = opts.plugins || [];
|
|
100
107
|
this.corsOpts = __assign(__assign({}, defaultCorsOptions), opts.cors);
|
|
101
108
|
this.auth = opts.auth;
|
|
109
|
+
this.jsonOptions = opts.jsonOptions || { limit: "1mb" };
|
|
110
|
+
this.schedulingOptions = opts.scheduling;
|
|
102
111
|
}
|
|
103
112
|
Object.defineProperty(FlinkApp.prototype, "ctx", {
|
|
104
113
|
get: function () {
|
|
@@ -125,22 +134,21 @@ var FlinkApp = /** @class */ (function () {
|
|
|
125
134
|
_c.sent();
|
|
126
135
|
if (this.debug) {
|
|
127
136
|
offsetTime = Date.now();
|
|
128
|
-
|
|
137
|
+
FlinkLog_1.log.bgColorLog("cyan", "Init db took ".concat(offsetTime - startTime, " ms"));
|
|
129
138
|
}
|
|
130
139
|
return [4 /*yield*/, this.buildContext()];
|
|
131
140
|
case 2:
|
|
132
141
|
_c.sent();
|
|
133
142
|
if (this.debug) {
|
|
134
|
-
|
|
143
|
+
FlinkLog_1.log.bgColorLog("cyan", "Build context took ".concat(Date.now() - offsetTime, " ms"));
|
|
135
144
|
offsetTime = Date.now();
|
|
136
145
|
}
|
|
137
|
-
if (this.
|
|
138
|
-
|
|
139
|
-
offsetTime = Date.now();
|
|
146
|
+
if (this.isSchedulingEnabled) {
|
|
147
|
+
this.scheduler = new toad_scheduler_1.ToadScheduler();
|
|
140
148
|
}
|
|
141
149
|
this.expressApp = (0, express_1.default)();
|
|
142
150
|
this.expressApp.use((0, cors_1.default)(this.corsOpts));
|
|
143
|
-
this.expressApp.use(body_parser_1.default.json());
|
|
151
|
+
this.expressApp.use(body_parser_1.default.json(this.jsonOptions));
|
|
144
152
|
this.expressApp.use(function (req, res, next) {
|
|
145
153
|
req.reqId = (0, uuid_1.v4)();
|
|
146
154
|
next();
|
|
@@ -163,7 +171,7 @@ var FlinkApp = /** @class */ (function () {
|
|
|
163
171
|
_c.sent();
|
|
164
172
|
_c.label = 7;
|
|
165
173
|
case 7:
|
|
166
|
-
|
|
174
|
+
FlinkLog_1.log.info("Initialized plugin '".concat(plugin.id, "'"));
|
|
167
175
|
_c.label = 8;
|
|
168
176
|
case 8:
|
|
169
177
|
_i++;
|
|
@@ -172,9 +180,19 @@ var FlinkApp = /** @class */ (function () {
|
|
|
172
180
|
case 10:
|
|
173
181
|
_c.sent();
|
|
174
182
|
if (this.debug) {
|
|
175
|
-
|
|
183
|
+
FlinkLog_1.log.bgColorLog("cyan", "Register handlers took ".concat(Date.now() - offsetTime, " ms"));
|
|
176
184
|
offsetTime = Date.now();
|
|
177
185
|
}
|
|
186
|
+
if (!this.isSchedulingEnabled) return [3 /*break*/, 12];
|
|
187
|
+
return [4 /*yield*/, this.registerAutoRegisterableJobs()];
|
|
188
|
+
case 11:
|
|
189
|
+
_c.sent();
|
|
190
|
+
if (this.debug) {
|
|
191
|
+
FlinkLog_1.log.bgColorLog("cyan", "Register jobs took ".concat(Date.now() - offsetTime, " ms"));
|
|
192
|
+
offsetTime = Date.now();
|
|
193
|
+
}
|
|
194
|
+
_c.label = 12;
|
|
195
|
+
case 12:
|
|
178
196
|
// Register 404 with slight delay to allow all manually added routes to be added
|
|
179
197
|
// TODO: Is there a better solution to force this handler to always run last?
|
|
180
198
|
setTimeout(function () {
|
|
@@ -184,7 +202,7 @@ var FlinkApp = /** @class */ (function () {
|
|
|
184
202
|
_this.routingConfigured = true;
|
|
185
203
|
});
|
|
186
204
|
(_a = this.expressApp) === null || _a === void 0 ? void 0 : _a.listen(this.port, function () {
|
|
187
|
-
|
|
205
|
+
FlinkLog_1.log.fontColorLog("magenta", "\u26A1\uFE0F HTTP server '".concat(_this.name, "' is running and waiting for connections on ").concat(_this.port));
|
|
188
206
|
_this.started = true;
|
|
189
207
|
});
|
|
190
208
|
return [2 /*return*/, this];
|
|
@@ -205,18 +223,18 @@ var FlinkApp = /** @class */ (function () {
|
|
|
205
223
|
}
|
|
206
224
|
var routeProps = __assign(__assign({}, (handler.Route || {})), routePropsOverride);
|
|
207
225
|
if (!routeProps.method) {
|
|
208
|
-
|
|
226
|
+
FlinkLog_1.log.error("Failed to register handler '".concat(handler.__file, "': Missing 'method' in route props, either set it or name handler file with HTTP method as prefix"));
|
|
209
227
|
return;
|
|
210
228
|
}
|
|
211
229
|
if (!routeProps.path) {
|
|
212
|
-
|
|
230
|
+
FlinkLog_1.log.error("Failed to register handler '".concat(handler.__file, "': Missing 'path' in route props"));
|
|
213
231
|
return;
|
|
214
232
|
}
|
|
215
233
|
var dup = this.handlers.find(function (h) { return h.routeProps.path === routeProps.path && h.routeProps.method === routeProps.method; });
|
|
216
234
|
var methodAndPath = "".concat(routeProps.method.toUpperCase(), " ").concat(routeProps.path);
|
|
217
235
|
if (dup) {
|
|
218
236
|
// TODO: Not sure if there is a case where you'd want to overwrite a route?
|
|
219
|
-
|
|
237
|
+
FlinkLog_1.log.warn("".concat(methodAndPath, " overlaps existing route"));
|
|
220
238
|
}
|
|
221
239
|
var handlerConfig = {
|
|
222
240
|
routeProps: __assign(__assign({}, routeProps), { method: routeProps.method, path: routeProps.path }),
|
|
@@ -228,10 +246,10 @@ var FlinkApp = /** @class */ (function () {
|
|
|
228
246
|
paramsMetadata: handler.__params || [],
|
|
229
247
|
};
|
|
230
248
|
if (((_c = handler.__schemas) === null || _c === void 0 ? void 0 : _c.reqSchema) && !((_d = handlerConfig.schema) === null || _d === void 0 ? void 0 : _d.reqSchema)) {
|
|
231
|
-
|
|
249
|
+
FlinkLog_1.log.warn("Expected request schema ".concat(handler.__schemas.reqSchema, " for handler ").concat(methodAndPath, " but no such schema was found"));
|
|
232
250
|
}
|
|
233
251
|
if (((_e = handler.__schemas) === null || _e === void 0 ? void 0 : _e.resSchema) && !((_f = handlerConfig.schema) === null || _f === void 0 ? void 0 : _f.resSchema)) {
|
|
234
|
-
|
|
252
|
+
FlinkLog_1.log.warn("Expected response schema ".concat(handler.__schemas.resSchema, " for handler ").concat(methodAndPath, " but no such schema was found"));
|
|
235
253
|
}
|
|
236
254
|
this.registerHandler(handlerConfig, handler.default);
|
|
237
255
|
};
|
|
@@ -242,7 +260,7 @@ var FlinkApp = /** @class */ (function () {
|
|
|
242
260
|
var method = routeProps.method;
|
|
243
261
|
var app = this.expressApp;
|
|
244
262
|
if (!method) {
|
|
245
|
-
|
|
263
|
+
FlinkLog_1.log.error("Route ".concat(routeProps.path, " is missing http method"));
|
|
246
264
|
}
|
|
247
265
|
if (method) {
|
|
248
266
|
var methodAndRoute_1 = "".concat(method.toUpperCase(), " ").concat(routeProps.path);
|
|
@@ -263,8 +281,8 @@ var FlinkApp = /** @class */ (function () {
|
|
|
263
281
|
validate = ajv.compile(schema.reqSchema);
|
|
264
282
|
valid = validate(req.body);
|
|
265
283
|
if (!valid) {
|
|
266
|
-
|
|
267
|
-
|
|
284
|
+
FlinkLog_1.log.warn("".concat(methodAndRoute_1, ": Bad request ").concat(JSON.stringify(validate.errors, null, 2)));
|
|
285
|
+
FlinkLog_1.log.debug("Invalid json: ".concat(JSON.stringify(req.body)));
|
|
268
286
|
return [2 /*return*/, res.status(400).json({
|
|
269
287
|
status: 400,
|
|
270
288
|
error: {
|
|
@@ -276,7 +294,7 @@ var FlinkApp = /** @class */ (function () {
|
|
|
276
294
|
}
|
|
277
295
|
}
|
|
278
296
|
if (routeProps.mockApi && schema.resSchema) {
|
|
279
|
-
|
|
297
|
+
FlinkLog_1.log.warn("Mock response for ".concat(req.method.toUpperCase(), " ").concat(req.path));
|
|
280
298
|
data = (0, mock_data_generator_1.default)(schema.resSchema);
|
|
281
299
|
res.status(200).json({
|
|
282
300
|
status: 200,
|
|
@@ -298,7 +316,7 @@ var FlinkApp = /** @class */ (function () {
|
|
|
298
316
|
return [3 /*break*/, 6];
|
|
299
317
|
case 5:
|
|
300
318
|
err_1 = _a.sent();
|
|
301
|
-
|
|
319
|
+
FlinkLog_1.log.warn("Handler '".concat(methodAndRoute_1, "' threw unhandled exception ").concat(err_1));
|
|
302
320
|
console.error(err_1);
|
|
303
321
|
return [2 /*return*/, res.status(500).json((0, FlinkErrors_1.internalServerError)(err_1))];
|
|
304
322
|
case 6:
|
|
@@ -306,8 +324,8 @@ var FlinkApp = /** @class */ (function () {
|
|
|
306
324
|
validate = ajv.compile(schema.resSchema);
|
|
307
325
|
valid = validate(JSON.parse(JSON.stringify(handlerRes.data)));
|
|
308
326
|
if (!valid) {
|
|
309
|
-
|
|
310
|
-
|
|
327
|
+
FlinkLog_1.log.warn("[".concat(req.reqId, "] ").concat(methodAndRoute_1, ": Bad response ").concat(JSON.stringify(validate.errors, null, 2)));
|
|
328
|
+
FlinkLog_1.log.debug("Invalid json: ".concat(JSON.stringify(handlerRes.data)));
|
|
311
329
|
// log.debug(JSON.stringify(schema, null, 2));
|
|
312
330
|
return [2 /*return*/, res.status(500).json({
|
|
313
331
|
status: 500,
|
|
@@ -326,12 +344,12 @@ var FlinkApp = /** @class */ (function () {
|
|
|
326
344
|
});
|
|
327
345
|
}); });
|
|
328
346
|
if (this.handlerRouteCache.has(methodAndRoute_1)) {
|
|
329
|
-
|
|
347
|
+
FlinkLog_1.log.error("Cannot register handler ".concat(methodAndRoute_1, " - route already registered"));
|
|
330
348
|
return process.exit(1); // TODO: Do we need to exit?
|
|
331
349
|
}
|
|
332
350
|
else {
|
|
333
351
|
this.handlerRouteCache.set(methodAndRoute_1, JSON.stringify(routeProps));
|
|
334
|
-
|
|
352
|
+
FlinkLog_1.log.info("Registered route ".concat(methodAndRoute_1));
|
|
335
353
|
}
|
|
336
354
|
}
|
|
337
355
|
};
|
|
@@ -349,11 +367,11 @@ var FlinkApp = /** @class */ (function () {
|
|
|
349
367
|
for (_i = 0, autoRegisteredHandlers_1 = exports.autoRegisteredHandlers; _i < autoRegisteredHandlers_1.length; _i++) {
|
|
350
368
|
_c = autoRegisteredHandlers_1[_i], handler = _c.handler, assumedHttpMethod = _c.assumedHttpMethod;
|
|
351
369
|
if (!handler.Route) {
|
|
352
|
-
|
|
370
|
+
FlinkLog_1.log.error("Missing Props in handler ".concat(handler.__file));
|
|
353
371
|
continue;
|
|
354
372
|
}
|
|
355
373
|
if (!handler.default) {
|
|
356
|
-
|
|
374
|
+
FlinkLog_1.log.error("Missing exported handler function in handler ".concat(handler.__file));
|
|
357
375
|
continue;
|
|
358
376
|
}
|
|
359
377
|
this.registerHandler({
|
|
@@ -370,6 +388,91 @@ var FlinkApp = /** @class */ (function () {
|
|
|
370
388
|
});
|
|
371
389
|
});
|
|
372
390
|
};
|
|
391
|
+
FlinkApp.prototype.registerAutoRegisterableJobs = function () {
|
|
392
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
393
|
+
var _loop_1, this_1, _i, autoRegisteredJobs_1, _a, jobProps, jobFn, __file;
|
|
394
|
+
var _this = this;
|
|
395
|
+
return __generator(this, function (_b) {
|
|
396
|
+
if (!this.scheduler) {
|
|
397
|
+
throw new Error("Scheduler not initialized"); // should never happen
|
|
398
|
+
}
|
|
399
|
+
_loop_1 = function (jobProps, jobFn, __file) {
|
|
400
|
+
if (jobProps.cron && jobProps.interval) {
|
|
401
|
+
FlinkLog_1.log.error("Cannot register job ".concat(jobProps.id, " - both cron and interval are set in ").concat(__file));
|
|
402
|
+
return "continue";
|
|
403
|
+
}
|
|
404
|
+
if (jobProps.cron && jobProps.afterDelay) {
|
|
405
|
+
FlinkLog_1.log.error("Cannot register job ".concat(jobProps.id, " - both cron and afterDelay are set in ").concat(__file));
|
|
406
|
+
return "continue";
|
|
407
|
+
}
|
|
408
|
+
if (jobProps.interval && jobProps.afterDelay) {
|
|
409
|
+
FlinkLog_1.log.error("Cannot register job ".concat(jobProps.id, " - both interval and afterDelay are set in ").concat(__file));
|
|
410
|
+
return "continue";
|
|
411
|
+
}
|
|
412
|
+
if (this_1.scheduler.existsById(jobProps.id)) {
|
|
413
|
+
FlinkLog_1.log.error("Job with id ".concat(jobProps.id, " is already registered, found duplicate in ").concat(__file));
|
|
414
|
+
return "continue";
|
|
415
|
+
}
|
|
416
|
+
FlinkLog_1.log.debug("Registering job ".concat(jobProps.id, ": ").concat(JSON.stringify(jobProps), " from ").concat(__file));
|
|
417
|
+
var task = new toad_scheduler_1.AsyncTask(jobProps.id, function () { return __awaiter(_this, void 0, void 0, function () {
|
|
418
|
+
return __generator(this, function (_a) {
|
|
419
|
+
switch (_a.label) {
|
|
420
|
+
case 0: return [4 /*yield*/, jobFn({ ctx: this.ctx })];
|
|
421
|
+
case 1:
|
|
422
|
+
_a.sent();
|
|
423
|
+
FlinkLog_1.log.debug("Job ".concat(jobProps.id, " completed"));
|
|
424
|
+
if (jobProps.afterDelay) {
|
|
425
|
+
// afterDelay runs only once, so we remove the job
|
|
426
|
+
this.scheduler.removeById(jobProps.id);
|
|
427
|
+
}
|
|
428
|
+
return [2 /*return*/];
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
}); }, function (err) {
|
|
432
|
+
FlinkLog_1.log.error("Job ".concat(jobProps.id, " threw unhandled exception ").concat(err));
|
|
433
|
+
console.error(err);
|
|
434
|
+
});
|
|
435
|
+
if (jobProps.cron) {
|
|
436
|
+
var job = new toad_scheduler_1.CronJob({ timezone: jobProps.timezone, cronExpression: jobProps.cron }, task, {
|
|
437
|
+
id: jobProps.id,
|
|
438
|
+
preventOverrun: jobProps.singleton,
|
|
439
|
+
});
|
|
440
|
+
this_1.scheduler.addCronJob(job);
|
|
441
|
+
}
|
|
442
|
+
else if (jobProps.interval) {
|
|
443
|
+
var job = new toad_scheduler_1.SimpleIntervalJob({
|
|
444
|
+
milliseconds: (0, ms_1.default)(jobProps.interval),
|
|
445
|
+
runImmediately: false, // TODO: Expose to props?
|
|
446
|
+
}, task, {
|
|
447
|
+
id: jobProps.id,
|
|
448
|
+
preventOverrun: jobProps.singleton,
|
|
449
|
+
});
|
|
450
|
+
this_1.scheduler.addSimpleIntervalJob(job);
|
|
451
|
+
}
|
|
452
|
+
else if (jobProps.afterDelay !== undefined) {
|
|
453
|
+
var job = new toad_scheduler_1.SimpleIntervalJob({
|
|
454
|
+
milliseconds: (0, ms_1.default)(jobProps.afterDelay),
|
|
455
|
+
runImmediately: false,
|
|
456
|
+
}, task, {
|
|
457
|
+
id: jobProps.id,
|
|
458
|
+
preventOverrun: jobProps.singleton,
|
|
459
|
+
});
|
|
460
|
+
this_1.scheduler.addSimpleIntervalJob(job);
|
|
461
|
+
}
|
|
462
|
+
else {
|
|
463
|
+
FlinkLog_1.log.error("Cannot register job ".concat(jobProps.id, " - no cron, interval or once set in ").concat(__file));
|
|
464
|
+
return "continue";
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
this_1 = this;
|
|
468
|
+
for (_i = 0, autoRegisteredJobs_1 = exports.autoRegisteredJobs; _i < autoRegisteredJobs_1.length; _i++) {
|
|
469
|
+
_a = autoRegisteredJobs_1[_i], jobProps = _a.Job, jobFn = _a.default, __file = _a.__file;
|
|
470
|
+
_loop_1(jobProps, jobFn, __file);
|
|
471
|
+
}
|
|
472
|
+
return [2 /*return*/];
|
|
473
|
+
});
|
|
474
|
+
});
|
|
475
|
+
};
|
|
373
476
|
FlinkApp.prototype.addRepo = function (instanceName, repoInstance) {
|
|
374
477
|
this.repos[instanceName] = repoInstance;
|
|
375
478
|
// TODO: Find out if we need to set ctx here or wanted not to if plugin has its own context
|
|
@@ -388,11 +491,11 @@ var FlinkApp = /** @class */ (function () {
|
|
|
388
491
|
_a = autoRegisteredRepos_1[_i], collectionName = _a.collectionName, repoInstanceName = _a.repoInstanceName, Repo = _a.Repo;
|
|
389
492
|
repoInstance = new Repo(collectionName, this.db);
|
|
390
493
|
this.repos[repoInstanceName] = repoInstance;
|
|
391
|
-
|
|
494
|
+
FlinkLog_1.log.info("Registered repo ".concat(repoInstanceName));
|
|
392
495
|
}
|
|
393
496
|
}
|
|
394
497
|
else if (exports.autoRegisteredRepos.length > 0) {
|
|
395
|
-
|
|
498
|
+
FlinkLog_1.log.warn("No db configured but found repo(s)");
|
|
396
499
|
}
|
|
397
500
|
pluginCtx = this.plugins.reduce(function (out, plugin) {
|
|
398
501
|
if (out[plugin.id]) {
|
|
@@ -427,7 +530,7 @@ var FlinkApp = /** @class */ (function () {
|
|
|
427
530
|
_a.label = 1;
|
|
428
531
|
case 1:
|
|
429
532
|
_a.trys.push([1, 3, , 4]);
|
|
430
|
-
|
|
533
|
+
FlinkLog_1.log.debug("Connecting to db");
|
|
431
534
|
return [4 /*yield*/, mongodb_1.default.connect(this.dbOpts.uri, {
|
|
432
535
|
useUnifiedTopology: true,
|
|
433
536
|
connectTimeoutMS: 4000,
|
|
@@ -438,7 +541,7 @@ var FlinkApp = /** @class */ (function () {
|
|
|
438
541
|
return [3 /*break*/, 4];
|
|
439
542
|
case 3:
|
|
440
543
|
err_2 = _a.sent();
|
|
441
|
-
|
|
544
|
+
FlinkLog_1.log.error("Failed to connect to db: " + err_2);
|
|
442
545
|
process.exit(1);
|
|
443
546
|
return [3 /*break*/, 4];
|
|
444
547
|
case 4:
|
|
@@ -467,7 +570,7 @@ var FlinkApp = /** @class */ (function () {
|
|
|
467
570
|
if (!plugin.db) return [3 /*break*/, 5];
|
|
468
571
|
if (!plugin.db.useHostDb) return [3 /*break*/, 1];
|
|
469
572
|
if (!this.db) {
|
|
470
|
-
|
|
573
|
+
FlinkLog_1.log.error("Plugin '".concat(this.name, " configured to use host app db, but no db exists in FlinkApp'"));
|
|
471
574
|
}
|
|
472
575
|
else {
|
|
473
576
|
return [2 /*return*/, this.db];
|
|
@@ -478,7 +581,7 @@ var FlinkApp = /** @class */ (function () {
|
|
|
478
581
|
_a.label = 2;
|
|
479
582
|
case 2:
|
|
480
583
|
_a.trys.push([2, 4, , 5]);
|
|
481
|
-
|
|
584
|
+
FlinkLog_1.log.debug("Connecting to '".concat(plugin.id, "' db"));
|
|
482
585
|
return [4 /*yield*/, mongodb_1.default.connect(plugin.db.uri, {
|
|
483
586
|
useUnifiedTopology: true,
|
|
484
587
|
})];
|
|
@@ -487,7 +590,7 @@ var FlinkApp = /** @class */ (function () {
|
|
|
487
590
|
return [2 /*return*/, client.db()];
|
|
488
591
|
case 4:
|
|
489
592
|
err_3 = _a.sent();
|
|
490
|
-
|
|
593
|
+
FlinkLog_1.log.error("Failed to connect to db defined in plugin '".concat(plugin.id, "': ") + err_3);
|
|
491
594
|
return [3 /*break*/, 5];
|
|
492
595
|
case 5: return [2 /*return*/];
|
|
493
596
|
}
|
|
@@ -511,6 +614,14 @@ var FlinkApp = /** @class */ (function () {
|
|
|
511
614
|
FlinkApp.prototype.getRegisteredRoutes = function () {
|
|
512
615
|
return Array.from(this.handlerRouteCache.values());
|
|
513
616
|
};
|
|
617
|
+
Object.defineProperty(FlinkApp.prototype, "isSchedulingEnabled", {
|
|
618
|
+
get: function () {
|
|
619
|
+
var _a;
|
|
620
|
+
return ((_a = this.schedulingOptions) === null || _a === void 0 ? void 0 : _a.enabled) !== false;
|
|
621
|
+
},
|
|
622
|
+
enumerable: false,
|
|
623
|
+
configurable: true
|
|
624
|
+
});
|
|
514
625
|
return FlinkApp;
|
|
515
626
|
}());
|
|
516
627
|
exports.FlinkApp = FlinkApp;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { FlinkContext } from "./FlinkContext";
|
|
2
|
+
export type FlinkJobProps = {
|
|
3
|
+
/**
|
|
4
|
+
* Id of job, must be unique
|
|
5
|
+
*/
|
|
6
|
+
id: string;
|
|
7
|
+
/**
|
|
8
|
+
* Cron expression for scheduling job with minute precision
|
|
9
|
+
* Example: * * * * *
|
|
10
|
+
*/
|
|
11
|
+
cron?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Timezone for cron expression
|
|
14
|
+
* Example: Europe/Stockholm
|
|
15
|
+
*/
|
|
16
|
+
timezone?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Interval for scheduling job
|
|
19
|
+
* Uses ms syntax, i.e. 1s, 1m, 1h, 1d
|
|
20
|
+
*/
|
|
21
|
+
interval?: string;
|
|
22
|
+
/**
|
|
23
|
+
* If true, job will only run once at startup after delay.
|
|
24
|
+
* Uses ms syntax, i.e. 1s, 1m, 1h, 1d
|
|
25
|
+
*/
|
|
26
|
+
afterDelay?: string;
|
|
27
|
+
/**
|
|
28
|
+
* If true, job will only one at a time.
|
|
29
|
+
*
|
|
30
|
+
* If a job is already running, the next invocation will be ignored and will be
|
|
31
|
+
* retried after the next interval.
|
|
32
|
+
*/
|
|
33
|
+
singleton?: boolean;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Type for Flink job function. This function should be default exported from
|
|
37
|
+
* a Job file and the body is what will be executed when the job is invoked.
|
|
38
|
+
*/
|
|
39
|
+
export interface FlinkJob<C extends FlinkContext> {
|
|
40
|
+
(params: {
|
|
41
|
+
ctx: C;
|
|
42
|
+
}): Promise<any>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Type for Job file.
|
|
46
|
+
*
|
|
47
|
+
* Describes shape of exports when using syntax like:
|
|
48
|
+
*
|
|
49
|
+
* `import * as FooJob from "./src/jobs/FooJob"
|
|
50
|
+
*/
|
|
51
|
+
export type FlinkJobFile = {
|
|
52
|
+
default: FlinkJob<any>;
|
|
53
|
+
Job: FlinkJobProps;
|
|
54
|
+
/**
|
|
55
|
+
* Typescript source file name, is set at compile time by Flink compiler.
|
|
56
|
+
*/
|
|
57
|
+
__file?: string;
|
|
58
|
+
};
|
package/dist/src/FlinkLog.d.ts
CHANGED
|
@@ -4,5 +4,21 @@ export declare const log: {
|
|
|
4
4
|
warn: (...args: any[]) => void;
|
|
5
5
|
error: (...args: any[]) => void;
|
|
6
6
|
json: (...args: any) => void;
|
|
7
|
+
bgColorLog: (ticket: "black" | "red" | "green" | "yellow" | "blue" | "magenta" | "cyan" | "white", text: string, setting?: {
|
|
8
|
+
bold?: boolean | undefined;
|
|
9
|
+
italic?: boolean | undefined;
|
|
10
|
+
dim?: boolean | undefined;
|
|
11
|
+
underscore?: boolean | undefined;
|
|
12
|
+
reverse?: boolean | undefined;
|
|
13
|
+
strikethrough?: boolean | undefined;
|
|
14
|
+
} | undefined) => void;
|
|
15
|
+
fontColorLog: (ticket: "black" | "red" | "green" | "yellow" | "blue" | "magenta" | "cyan" | "white", text: string, setting?: {
|
|
16
|
+
bold?: boolean | undefined;
|
|
17
|
+
italic?: boolean | undefined;
|
|
18
|
+
dim?: boolean | undefined;
|
|
19
|
+
underscore?: boolean | undefined;
|
|
20
|
+
reverse?: boolean | undefined;
|
|
21
|
+
strikethrough?: boolean | undefined;
|
|
22
|
+
} | undefined) => void;
|
|
7
23
|
setLevel: (level: "debug" | "info" | "warn" | "error") => void;
|
|
8
24
|
};
|