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.
@@ -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.log(`定时器【${name}】执行成功,耗时${Date.now() - start}毫秒】,错误是`, err);
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.warn(`例程【${routine.name}】执行成功,耗时${Date.now() - start}毫秒,结果是`, result);
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);
@@ -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 fetch(finalApi, {
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.9",
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.2",
23
+ "oak-common-aspect": "^3.0.4",
24
24
  "oak-db": "^3.3.2",
25
- "oak-domain": "^5.1.9",
26
- "oak-frontend-base": "^5.3.18",
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"