oak-backend-base 4.1.23 → 4.1.25
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/lib/AppLoader.d.ts +13 -0
- package/lib/AppLoader.js +91 -0
- package/lib/types/index.d.ts +9 -0
- package/lib/types/index.js +2 -0
- package/package.json +3 -3
package/lib/AppLoader.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { Namespace } from 'socket.io';
|
|
|
7
7
|
import DataSubscriber from './cluster/DataSubscriber';
|
|
8
8
|
import Synchronizer from './Synchronizer';
|
|
9
9
|
import { AsyncContext } from 'oak-domain/lib/store/AsyncRowStore';
|
|
10
|
+
import { InternalErrorHandler } from './types';
|
|
10
11
|
export declare class AppLoader<ED extends EntityDict & BaseEntityDict, Cxt extends BackendRuntimeContext<ED>> extends GeneralAppLoader<ED, Cxt> {
|
|
11
12
|
protected dbStore: DbStore<ED, Cxt>;
|
|
12
13
|
private aspectDict;
|
|
@@ -17,6 +18,17 @@ export declare class AppLoader<ED extends EntityDict & BaseEntityDict, Cxt exten
|
|
|
17
18
|
private nsSocket?;
|
|
18
19
|
private watcherTimerId?;
|
|
19
20
|
private scheduledJobs;
|
|
21
|
+
private internalErrorHandlers;
|
|
22
|
+
regAllExceptionHandler(): void;
|
|
23
|
+
/**
|
|
24
|
+
* 注册一个内部错误处理器
|
|
25
|
+
* @param handler 内部错误处理器
|
|
26
|
+
*/
|
|
27
|
+
registerInternalErrorHandler(handler: InternalErrorHandler<ED, Cxt>): void;
|
|
28
|
+
/**
|
|
29
|
+
* 发布内部错误事件给注册的处理器
|
|
30
|
+
*/
|
|
31
|
+
private publishInternalError;
|
|
20
32
|
private requireSth;
|
|
21
33
|
protected makeContext(cxtStr?: string, headers?: IncomingHttpHeaders): Promise<Cxt>;
|
|
22
34
|
/**
|
|
@@ -50,5 +62,6 @@ export declare class AppLoader<ED extends EntityDict & BaseEntityDict, Cxt exten
|
|
|
50
62
|
protected execFreeTimer(timer: FreeTimer<ED, Cxt>, context: Cxt): Promise<OperationResult<ED>> | undefined;
|
|
51
63
|
startTimers(): void;
|
|
52
64
|
execStartRoutines(): Promise<void>;
|
|
65
|
+
execStopRoutines(): Promise<void>;
|
|
53
66
|
execRoutine(routine: <Cxt extends AsyncContext<ED>>(context: Cxt) => Promise<void>): Promise<void>;
|
|
54
67
|
}
|
package/lib/AppLoader.js
CHANGED
|
@@ -28,6 +28,53 @@ class AppLoader extends types_1.AppLoader {
|
|
|
28
28
|
nsSocket;
|
|
29
29
|
watcherTimerId;
|
|
30
30
|
scheduledJobs = {};
|
|
31
|
+
internalErrorHandlers = new Array();
|
|
32
|
+
regAllExceptionHandler() {
|
|
33
|
+
const handlers = this.requireSth('lib/configuration/exception');
|
|
34
|
+
if (Array.isArray(handlers)) {
|
|
35
|
+
handlers.forEach((handler) => {
|
|
36
|
+
console.log(`注册内部错误处理器: ${handler.name}`);
|
|
37
|
+
this.registerInternalErrorHandler(handler);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
console.warn('lib/configuration/exception必须默认导出一个处理器数组,当前导出类型不正确,将忽略此配置');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* 注册一个内部错误处理器
|
|
46
|
+
* @param handler 内部错误处理器
|
|
47
|
+
*/
|
|
48
|
+
registerInternalErrorHandler(handler) {
|
|
49
|
+
// 检查有没有名称重复
|
|
50
|
+
if (this.internalErrorHandlers.find(h => h.name === handler.name)) {
|
|
51
|
+
throw new Error(`内部错误处理器名称重复: ${handler.name}`);
|
|
52
|
+
}
|
|
53
|
+
this.internalErrorHandlers.push(handler);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 发布内部错误事件给注册的处理器
|
|
57
|
+
*/
|
|
58
|
+
async publishInternalError(type, message, err) {
|
|
59
|
+
const errorToPublish = (0, lodash_1.cloneDeep)(err);
|
|
60
|
+
await Promise.all(this.internalErrorHandlers.map((handler) => {
|
|
61
|
+
return new Promise(async (resolve) => {
|
|
62
|
+
const ctx = await this.makeContext();
|
|
63
|
+
try {
|
|
64
|
+
console.log(`调用internalErrorHandler【${handler.name}】处理内部错误事件`);
|
|
65
|
+
await handler.handle(ctx, type, message, errorToPublish);
|
|
66
|
+
await ctx.commit();
|
|
67
|
+
}
|
|
68
|
+
catch (e) {
|
|
69
|
+
console.error('执行internalErrorHandler时出错', e);
|
|
70
|
+
await ctx.rollback();
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
resolve();
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
31
78
|
requireSth(filePath) {
|
|
32
79
|
return (0, requirePrj_1.default)(this.path, filePath, this.externalDependencies);
|
|
33
80
|
}
|
|
@@ -172,7 +219,9 @@ class AppLoader extends types_1.AppLoader {
|
|
|
172
219
|
};
|
|
173
220
|
}
|
|
174
221
|
catch (err) {
|
|
222
|
+
console.error(`执行aspect「${name}」出错`, err);
|
|
175
223
|
await context.rollback();
|
|
224
|
+
this.publishInternalError(`aspect`, `执行aspect「${name}」出错`, err);
|
|
176
225
|
if (err instanceof types_1.OakException) {
|
|
177
226
|
throw err;
|
|
178
227
|
}
|
|
@@ -357,6 +406,7 @@ class AppLoader extends types_1.AppLoader {
|
|
|
357
406
|
else {
|
|
358
407
|
await context.rollback();
|
|
359
408
|
}
|
|
409
|
+
// 不能在这里publish,因为这个方法可能是在timer中调用,也可能是在routine中调用
|
|
360
410
|
throw err;
|
|
361
411
|
}
|
|
362
412
|
}
|
|
@@ -382,6 +432,7 @@ class AppLoader extends types_1.AppLoader {
|
|
|
382
432
|
}
|
|
383
433
|
catch (err) {
|
|
384
434
|
console.error(`执行watcher【${watcher.name}】失败,耗时【${Date.now() - start}】,结果是:`, err);
|
|
435
|
+
await this.publishInternalError(`watcher`, `执行watcher【${watcher.name}】失败`, err);
|
|
385
436
|
}
|
|
386
437
|
};
|
|
387
438
|
const doWatchers = async () => {
|
|
@@ -400,6 +451,7 @@ class AppLoader extends types_1.AppLoader {
|
|
|
400
451
|
}
|
|
401
452
|
catch (err) {
|
|
402
453
|
console.error(`执行了checkpoint,发生错误:`, err);
|
|
454
|
+
await this.publishInternalError(`checkpoint`, `执行checkpoint发生错误`, err);
|
|
403
455
|
}
|
|
404
456
|
this.watcherTimerId = setTimeout(() => doWatchers(), 120000);
|
|
405
457
|
};
|
|
@@ -424,6 +476,7 @@ class AppLoader extends types_1.AppLoader {
|
|
|
424
476
|
}
|
|
425
477
|
catch (err) {
|
|
426
478
|
console.error(`定时器【${name}】执行失败,耗时${Date.now() - start}毫秒】,错误是`, err);
|
|
479
|
+
this.publishInternalError(`timer`, `定时器【${name}】执行失败`, err);
|
|
427
480
|
}
|
|
428
481
|
}
|
|
429
482
|
else {
|
|
@@ -443,6 +496,7 @@ class AppLoader extends types_1.AppLoader {
|
|
|
443
496
|
else {
|
|
444
497
|
await context.rollback();
|
|
445
498
|
}
|
|
499
|
+
this.publishInternalError(`timer`, `定时器【${name}】执行失败`, err);
|
|
446
500
|
}
|
|
447
501
|
}
|
|
448
502
|
});
|
|
@@ -461,6 +515,42 @@ class AppLoader extends types_1.AppLoader {
|
|
|
461
515
|
async execStartRoutines() {
|
|
462
516
|
const routines = this.requireSth('lib/routines/start') || [];
|
|
463
517
|
for (const routine of routines) {
|
|
518
|
+
console.log(`执行启动例程【${routine.name}】...`);
|
|
519
|
+
if (routine.hasOwnProperty('entity')) {
|
|
520
|
+
const start = Date.now();
|
|
521
|
+
try {
|
|
522
|
+
const result = await this.execWatcher(routine);
|
|
523
|
+
console.log(`例程【${routine.name}】执行成功,耗时${Date.now() - start}毫秒,结果是`, result);
|
|
524
|
+
}
|
|
525
|
+
catch (err) {
|
|
526
|
+
console.error(`例程【${routine.name}】执行失败,耗时${Date.now() - start}毫秒,错误是`, err);
|
|
527
|
+
throw err;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
else {
|
|
531
|
+
const { name, routine: routineFn } = routine;
|
|
532
|
+
const context = await this.makeContext();
|
|
533
|
+
const start = Date.now();
|
|
534
|
+
try {
|
|
535
|
+
const result = await routineFn(context, {
|
|
536
|
+
socket: this.nsSocket,
|
|
537
|
+
contextBuilder: () => this.makeContext(),
|
|
538
|
+
});
|
|
539
|
+
console.log(`例程【${name}】执行成功,耗时${Date.now() - start}毫秒,结果是【${result}】`);
|
|
540
|
+
await context.commit();
|
|
541
|
+
}
|
|
542
|
+
catch (err) {
|
|
543
|
+
console.error(`例程【${name}】执行失败,耗时${Date.now() - start}毫秒,错误是`, err);
|
|
544
|
+
await context.rollback();
|
|
545
|
+
throw err;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
async execStopRoutines() {
|
|
551
|
+
const routines = this.requireSth('lib/routines/stop') || [];
|
|
552
|
+
for (const routine of routines) {
|
|
553
|
+
console.log(`执行停止例程【${routine.name}】...`);
|
|
464
554
|
if (routine.hasOwnProperty('entity')) {
|
|
465
555
|
const start = Date.now();
|
|
466
556
|
try {
|
|
@@ -479,6 +569,7 @@ class AppLoader extends types_1.AppLoader {
|
|
|
479
569
|
try {
|
|
480
570
|
const result = await routineFn(context, {
|
|
481
571
|
socket: this.nsSocket,
|
|
572
|
+
contextBuilder: () => this.makeContext(),
|
|
482
573
|
});
|
|
483
574
|
console.log(`例程【${name}】执行成功,耗时${Date.now() - start}毫秒,结果是【${result}】`);
|
|
484
575
|
await context.commit();
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BaseEntityDict } from "oak-domain";
|
|
2
|
+
import { AsyncContext } from "oak-domain/lib/store/AsyncRowStore";
|
|
3
|
+
import { EntityDict } from "oak-domain/lib/types";
|
|
4
|
+
export type InternalErrorType = 'aspect' | 'trigger' | 'watcher' | 'timer' | 'checkpoint';
|
|
5
|
+
export type InternalErrorHandler<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>> = {
|
|
6
|
+
name: string;
|
|
7
|
+
handle: (ctx: Cxt, type: InternalErrorType, message: string, err: Error) => Promise<void>;
|
|
8
|
+
};
|
|
9
|
+
export type ExceptionPublisher = (type: string, message: string, err: any) => Promise<void>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oak-backend-base",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.25",
|
|
4
4
|
"description": "oak-backend-base",
|
|
5
5
|
"main": "lib/index",
|
|
6
6
|
"author": {
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"node-schedule": "^2.1.0",
|
|
24
24
|
"oak-common-aspect": "^3.0.5",
|
|
25
25
|
"oak-db": "^3.3.11",
|
|
26
|
-
"oak-domain": "^5.1.
|
|
27
|
-
"oak-frontend-base": "^5.3.
|
|
26
|
+
"oak-domain": "^5.1.31",
|
|
27
|
+
"oak-frontend-base": "^5.3.43",
|
|
28
28
|
"socket.io": "^4.8.1",
|
|
29
29
|
"socket.io-client": "^4.7.2",
|
|
30
30
|
"uuid": "^8.3.2"
|