oak-backend-base 4.1.9 → 4.1.11
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 +2 -0
- package/lib/AppLoader.js +19 -4
- package/lib/Synchronizer.js +32 -8
- package/package.json +4 -4
package/lib/AppLoader.d.ts
CHANGED
|
@@ -16,6 +16,8 @@ export declare class AppLoader<ED extends EntityDict & BaseEntityDict, Cxt exten
|
|
|
16
16
|
protected synchronizer?: Synchronizer<ED, Cxt>;
|
|
17
17
|
protected contextBuilder: (store: DbStore<ED, Cxt>) => Cxt;
|
|
18
18
|
private nsSocket?;
|
|
19
|
+
private watcherTimerId?;
|
|
20
|
+
private scheduledJobs;
|
|
19
21
|
private requireSth;
|
|
20
22
|
protected makeContext(cxtStr?: string, headers?: IncomingHttpHeaders): Promise<Cxt>;
|
|
21
23
|
/**
|
package/lib/AppLoader.js
CHANGED
|
@@ -24,6 +24,8 @@ class AppLoader extends types_1.AppLoader {
|
|
|
24
24
|
synchronizer;
|
|
25
25
|
contextBuilder;
|
|
26
26
|
nsSocket;
|
|
27
|
+
watcherTimerId;
|
|
28
|
+
scheduledJobs = {};
|
|
27
29
|
requireSth(filePath) {
|
|
28
30
|
const depFilePath = (0, path_1.join)(this.path, filePath);
|
|
29
31
|
let sth;
|
|
@@ -149,6 +151,14 @@ class AppLoader extends types_1.AppLoader {
|
|
|
149
151
|
this.dbStore.connect();
|
|
150
152
|
}
|
|
151
153
|
async unmount() {
|
|
154
|
+
if (this.watcherTimerId) {
|
|
155
|
+
console.log('取消watcher...');
|
|
156
|
+
clearTimeout(this.watcherTimerId);
|
|
157
|
+
}
|
|
158
|
+
for (const job in this.scheduledJobs) {
|
|
159
|
+
console.log(`取消定时任务【${job}】...`);
|
|
160
|
+
this.scheduledJobs[job].cancel();
|
|
161
|
+
}
|
|
152
162
|
(0, index_1.clearPorts)();
|
|
153
163
|
this.dbStore.disconnect();
|
|
154
164
|
}
|
|
@@ -369,7 +379,7 @@ class AppLoader extends types_1.AppLoader {
|
|
|
369
379
|
catch (err) {
|
|
370
380
|
console.error(`执行了checkpoint,发生错误:`, err);
|
|
371
381
|
}
|
|
372
|
-
setTimeout(() => doWatchers(), 120000);
|
|
382
|
+
this.watcherTimerId = setTimeout(() => doWatchers(), 120000);
|
|
373
383
|
};
|
|
374
384
|
doWatchers();
|
|
375
385
|
}
|
|
@@ -382,7 +392,7 @@ class AppLoader extends types_1.AppLoader {
|
|
|
382
392
|
if (timers) {
|
|
383
393
|
for (const timer of timers) {
|
|
384
394
|
const { cron, name } = timer;
|
|
385
|
-
(0, node_schedule_1.scheduleJob)(name, cron, async (date) => {
|
|
395
|
+
const job = (0, node_schedule_1.scheduleJob)(name, cron, async (date) => {
|
|
386
396
|
const start = Date.now();
|
|
387
397
|
console.log(`定时器【${name}】开始执行,时间是【${date.toLocaleTimeString()}】`);
|
|
388
398
|
if (timer.hasOwnProperty('entity')) {
|
|
@@ -391,7 +401,7 @@ class AppLoader extends types_1.AppLoader {
|
|
|
391
401
|
console.log(`定时器【${name}】执行成功,耗时${Date.now() - start}毫秒】,结果是`, result);
|
|
392
402
|
}
|
|
393
403
|
catch (err) {
|
|
394
|
-
console.
|
|
404
|
+
console.warn(`定时器【${name}】执行失败,耗时${Date.now() - start}毫秒】,错误是`, err);
|
|
395
405
|
}
|
|
396
406
|
}
|
|
397
407
|
else {
|
|
@@ -414,6 +424,11 @@ class AppLoader extends types_1.AppLoader {
|
|
|
414
424
|
}
|
|
415
425
|
}
|
|
416
426
|
});
|
|
427
|
+
if (this.scheduledJobs[name]) {
|
|
428
|
+
// console.error(`定时器【${name}】已经存在,请检查定时器名称是否重复`);
|
|
429
|
+
throw new Error(`定时器【${name}】已经存在,请检查定时器名称是否重复`);
|
|
430
|
+
}
|
|
431
|
+
this.scheduledJobs[name] = job;
|
|
417
432
|
}
|
|
418
433
|
}
|
|
419
434
|
}
|
|
@@ -424,7 +439,7 @@ class AppLoader extends types_1.AppLoader {
|
|
|
424
439
|
const start = Date.now();
|
|
425
440
|
try {
|
|
426
441
|
const result = await this.execWatcher(routine);
|
|
427
|
-
console.
|
|
442
|
+
console.log(`例程【${routine.name}】执行成功,耗时${Date.now() - start}毫秒,结果是`, result);
|
|
428
443
|
}
|
|
429
444
|
catch (err) {
|
|
430
445
|
console.warn(`例程【${routine.name}】执行失败,耗时${Date.now() - start}毫秒,错误是`, err);
|
package/lib/Synchronizer.js
CHANGED
|
@@ -37,6 +37,27 @@ function verify(publicKey, body, ts, nonce, signature) {
|
|
|
37
37
|
verify2.end();
|
|
38
38
|
return verify2.verify(publicKey, signature, 'hex');
|
|
39
39
|
}
|
|
40
|
+
async function fetchWithTimeout(url, options, timeout = 5000) {
|
|
41
|
+
const controller = new AbortController();
|
|
42
|
+
const signal = controller.signal;
|
|
43
|
+
// 设置超时
|
|
44
|
+
const timeoutId = setTimeout(() => {
|
|
45
|
+
controller.abort();
|
|
46
|
+
}, timeout);
|
|
47
|
+
// 发起 fetch 请求并传递 signal
|
|
48
|
+
return fetch(url, Object.assign({}, options, { signal }))
|
|
49
|
+
.then(response => {
|
|
50
|
+
clearTimeout(timeoutId); // 如果请求成功,清除超时
|
|
51
|
+
return response;
|
|
52
|
+
})
|
|
53
|
+
.catch(error => {
|
|
54
|
+
clearTimeout(timeoutId); // 如果请求失败,清除超时
|
|
55
|
+
if (error.name === 'AbortError') {
|
|
56
|
+
throw new types_1.OakRequestTimeoutException();
|
|
57
|
+
}
|
|
58
|
+
throw error; // 其他错误
|
|
59
|
+
});
|
|
60
|
+
}
|
|
40
61
|
class Synchronizer {
|
|
41
62
|
config;
|
|
42
63
|
schema;
|
|
@@ -45,7 +66,7 @@ class Synchronizer {
|
|
|
45
66
|
contextBuilder;
|
|
46
67
|
pushAccessMap = {};
|
|
47
68
|
async startChannel2(context, channel) {
|
|
48
|
-
const { queue, api, selfEncryptInfo, entity, entityId, onFailed } = channel;
|
|
69
|
+
const { queue, api, selfEncryptInfo, entity, entityId, onFailed, timeout } = channel;
|
|
49
70
|
// todo 加密
|
|
50
71
|
const opers = queue.map(ele => ele.oper);
|
|
51
72
|
if (process.env.NODE_ENV === 'development') {
|
|
@@ -59,7 +80,7 @@ class Synchronizer {
|
|
|
59
80
|
try {
|
|
60
81
|
const body = JSON.stringify(opers);
|
|
61
82
|
const { ts, nonce, signature } = await sign(selfEncryptInfo.privateKey, body);
|
|
62
|
-
const res = await
|
|
83
|
+
const res = await fetchWithTimeout(finalApi, {
|
|
63
84
|
method: 'post',
|
|
64
85
|
headers: {
|
|
65
86
|
'Content-Type': 'application/json',
|
|
@@ -70,7 +91,7 @@ class Synchronizer {
|
|
|
70
91
|
[OAK_SYNC_HEADER_SIGN]: signature,
|
|
71
92
|
},
|
|
72
93
|
body,
|
|
73
|
-
});
|
|
94
|
+
}, timeout || 5000);
|
|
74
95
|
if (res.status !== 200) {
|
|
75
96
|
throw new Error(`sync数据时,访问api「${finalApi}」的结果不是200。「${res.status}」`);
|
|
76
97
|
}
|
|
@@ -90,7 +111,7 @@ class Synchronizer {
|
|
|
90
111
|
remoteEntityId: entityId,
|
|
91
112
|
data: queue.map((ele) => ({
|
|
92
113
|
entity: ele.oper.targetEntity,
|
|
93
|
-
rowIds: ele.oper.filter.id.$in,
|
|
114
|
+
rowIds: ele.oper.filter.id.$in, // 暂时应该没什么用
|
|
94
115
|
action: ele.oper.action,
|
|
95
116
|
data: ele.oper.data,
|
|
96
117
|
})),
|
|
@@ -164,7 +185,7 @@ class Synchronizer {
|
|
|
164
185
|
}
|
|
165
186
|
}));
|
|
166
187
|
}
|
|
167
|
-
pushOperToChannel(oper, userId, url, endpoint, remoteEntity, remoteEntityId, selfEncryptInfo, onSynchronized, onFailed) {
|
|
188
|
+
pushOperToChannel(oper, userId, url, endpoint, remoteEntity, remoteEntityId, selfEncryptInfo, onSynchronized, onFailed, timeout) {
|
|
168
189
|
if (!this.channelDict[userId]) {
|
|
169
190
|
// channel上缓存这些信息,暂不支持动态更新
|
|
170
191
|
this.channelDict[userId] = {
|
|
@@ -174,6 +195,7 @@ class Synchronizer {
|
|
|
174
195
|
entityId: remoteEntityId,
|
|
175
196
|
selfEncryptInfo,
|
|
176
197
|
onFailed,
|
|
198
|
+
timeout,
|
|
177
199
|
};
|
|
178
200
|
}
|
|
179
201
|
else {
|
|
@@ -220,7 +242,7 @@ class Synchronizer {
|
|
|
220
242
|
if (pushEntityNodes && pushEntityNodes.length > 0) {
|
|
221
243
|
// 每个pushEntityNode代表配置的一个remoteEntity
|
|
222
244
|
await Promise.all(pushEntityNodes.map(async (node) => {
|
|
223
|
-
const { projection, groupByUsers, getRemotePushInfo: getRemoteAccessInfo, groupBySelfEntity, endpoint, actions, onSynchronized, onFailed } = node;
|
|
245
|
+
const { projection, groupByUsers, getRemotePushInfo: getRemoteAccessInfo, groupBySelfEntity, endpoint, actions, onSynchronized, onFailed, timeout } = node;
|
|
224
246
|
// 定义中应该不可能没有actions
|
|
225
247
|
if (!actions || actions.includes(action)) {
|
|
226
248
|
const rows = await context.select(targetEntity, {
|
|
@@ -254,7 +276,7 @@ class Synchronizer {
|
|
|
254
276
|
userId,
|
|
255
277
|
remoteEntityId: entityId,
|
|
256
278
|
});
|
|
257
|
-
this.pushOperToChannel(oper2, userId, url, endpoint, entity, entityId, selfEncryptInfo, onSynchronized, onFailed);
|
|
279
|
+
this.pushOperToChannel(oper2, userId, url, endpoint, entity, entityId, selfEncryptInfo, onSynchronized, onFailed, timeout);
|
|
258
280
|
};
|
|
259
281
|
for (const userId in userSendDict) {
|
|
260
282
|
if (userId !== operatorId || !oper.bornAt) {
|
|
@@ -365,7 +387,7 @@ class Synchronizer {
|
|
|
365
387
|
const { remotes, self } = config;
|
|
366
388
|
// 根据remotes定义,建立从entity到需要同步的远端结点信息的Map
|
|
367
389
|
remotes.forEach((remote) => {
|
|
368
|
-
const { getPushInfo, pushEntities: pushEntityDefs, endpoint, pathToUser, relationName: rnRemote, onFailed } = remote;
|
|
390
|
+
const { getPushInfo, pushEntities: pushEntityDefs, endpoint, pathToUser, relationName: rnRemote, onFailed, timeout } = remote;
|
|
369
391
|
if (pushEntityDefs) {
|
|
370
392
|
const pushEntities = [];
|
|
371
393
|
const endpoint2 = (0, path_1.join)(endpoint || 'sync', self.entity);
|
|
@@ -433,6 +455,7 @@ class Synchronizer {
|
|
|
433
455
|
actions,
|
|
434
456
|
onSynchronized,
|
|
435
457
|
onFailed,
|
|
458
|
+
timeout,
|
|
436
459
|
}];
|
|
437
460
|
}
|
|
438
461
|
else {
|
|
@@ -446,6 +469,7 @@ class Synchronizer {
|
|
|
446
469
|
actions,
|
|
447
470
|
onSynchronized,
|
|
448
471
|
onFailed,
|
|
472
|
+
timeout,
|
|
449
473
|
});
|
|
450
474
|
}
|
|
451
475
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oak-backend-base",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.11",
|
|
4
4
|
"description": "oak-backend-base",
|
|
5
5
|
"main": "lib/index",
|
|
6
6
|
"author": {
|
|
@@ -20,10 +20,10 @@
|
|
|
20
20
|
"mysql": "^2.18.1",
|
|
21
21
|
"mysql2": "^2.3.3",
|
|
22
22
|
"node-schedule": "^2.1.0",
|
|
23
|
-
"oak-common-aspect": "^3.0.
|
|
23
|
+
"oak-common-aspect": "^3.0.4",
|
|
24
24
|
"oak-db": "^3.3.2",
|
|
25
|
-
"oak-domain": "^5.1.
|
|
26
|
-
"oak-frontend-base": "^5.3.
|
|
25
|
+
"oak-domain": "^5.1.11",
|
|
26
|
+
"oak-frontend-base": "^5.3.20",
|
|
27
27
|
"socket.io": "^4.7.2",
|
|
28
28
|
"socket.io-client": "^4.7.2",
|
|
29
29
|
"uuid": "^8.3.2"
|