@jayfong/x-server 1.35.2 → 1.35.4

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.
@@ -6,6 +6,8 @@ exports.__esModule = true;
6
6
  exports.defineSliceTask = defineSliceTask;
7
7
  exports.defineTask = defineTask;
8
8
 
9
+ var _assert = _interopRequireDefault(require("assert"));
10
+
9
11
  var _bull = _interopRequireDefault(require("bull"));
10
12
 
11
13
  var _date = require("vtils/date");
@@ -37,25 +39,65 @@ function defineSliceTask(options) {
37
39
  name: options.name,
38
40
  concurrency: 1,
39
41
  handle: async data => {
40
- const res = await _x.x.redis.multi([['lrange', data.redisKey, '0', '-1'], ['del', data.redisKey]]).exec();
41
- const list = res[0][1].map(item => JSON.parse(item));
42
- return options.handle(list, data.key);
42
+ const res = data.count ? await _x.x.redis.multi([['lrange', data.redisKey, `-${data.count}`, '-1'], ['ltrim', data.redisKey, '0', `-${data.count + 1}`]]).exec() : await _x.x.redis.multi([['lrange', data.redisKey, '0', '-1'], ['del', data.redisKey]]).exec();
43
+ const list = res[0][1].reverse().map(item => JSON.parse(item));
44
+
45
+ if (list.length) {
46
+ return options.handle(list, data.key);
47
+ }
43
48
  }
44
49
  });
45
50
  const redisKeyPrefix = `${_x.x.appId}_batch_task_${options.name}`;
46
51
  const res = {
47
52
  add: async (data, addOptions) => {
48
53
  const key = (addOptions == null ? void 0 : addOptions.key) || '';
54
+ const duration = (addOptions == null ? void 0 : addOptions.duration) != null ? (0, _date.ms)(addOptions.duration) : typeof options.duration === 'function' ? (0, _date.ms)(options.duration(key)) : options.duration && (0, _date.ms)(options.duration);
55
+ const threshold = (addOptions == null ? void 0 : addOptions.threshold) || typeof options.threshold && (typeof options.threshold === 'function' ? options.threshold(key) : options.threshold);
56
+ (0, _assert.default)(duration != null || threshold != null, '参数 threshold 和 duration 必须至少设置 1 个');
49
57
  const redisKey = !key ? redisKeyPrefix : `${redisKeyPrefix}_${key}`;
50
58
  const res = await _x.x.redis.multi([['llen', redisKey], ['lpush', redisKey, JSON.stringify(data)]]).exec();
59
+ const count = parseInt(res[0][1], 10) + 1; // 时段与阈值并存
60
+ // 满10条推送,若超过1分钟仍未满10条,则亦推送
51
61
 
52
- if (parseInt(res[0][1], 10) === 0) {
62
+ if (duration != null && threshold != null) {
63
+ const delayTaskId = redisKey;
64
+ await task.getJob(delayTaskId).then(job => job == null ? void 0 : job.remove());
53
65
  await task.add({
54
66
  key: key,
55
67
  redisKey: redisKey
56
68
  }, {
57
- delay: (addOptions == null ? void 0 : addOptions.duration) != null ? (0, _date.ms)(addOptions.duration) : typeof options.duration === 'function' ? (0, _date.ms)(options.duration(key)) : (0, _date.ms)(options.duration)
69
+ jobId: delayTaskId,
70
+ delay: duration
58
71
  });
72
+
73
+ if (count === threshold) {
74
+ await task.add({
75
+ key: key,
76
+ redisKey: redisKey,
77
+ count: threshold
78
+ });
79
+ }
80
+ } // 仅时段
81
+ // 1分钟内的合并推送
82
+ else if (duration != null) {
83
+ if (count === 1) {
84
+ await task.add({
85
+ key: key,
86
+ redisKey: redisKey
87
+ }, {
88
+ delay: duration
89
+ });
90
+ }
91
+ } // 仅阈值
92
+ // 满10条推送
93
+ else if (threshold != null) {
94
+ if (count === threshold) {
95
+ await task.add({
96
+ key: key,
97
+ redisKey: redisKey,
98
+ count: threshold
99
+ });
100
+ }
59
101
  }
60
102
  }
61
103
  };
@@ -1,3 +1,4 @@
1
+ import assert from 'assert';
1
2
  import Queue from 'bull';
2
3
  import { ms } from 'vtils/date';
3
4
  import { x } from "../x";
@@ -25,25 +26,65 @@ export function defineSliceTask(options) {
25
26
  name: options.name,
26
27
  concurrency: 1,
27
28
  handle: async data => {
28
- const res = await x.redis.multi([['lrange', data.redisKey, '0', '-1'], ['del', data.redisKey]]).exec();
29
- const list = res[0][1].map(item => JSON.parse(item));
30
- return options.handle(list, data.key);
29
+ const res = data.count ? await x.redis.multi([['lrange', data.redisKey, `-${data.count}`, '-1'], ['ltrim', data.redisKey, '0', `-${data.count + 1}`]]).exec() : await x.redis.multi([['lrange', data.redisKey, '0', '-1'], ['del', data.redisKey]]).exec();
30
+ const list = res[0][1].reverse().map(item => JSON.parse(item));
31
+
32
+ if (list.length) {
33
+ return options.handle(list, data.key);
34
+ }
31
35
  }
32
36
  });
33
37
  const redisKeyPrefix = `${x.appId}_batch_task_${options.name}`;
34
38
  const res = {
35
39
  add: async (data, addOptions) => {
36
40
  const key = (addOptions == null ? void 0 : addOptions.key) || '';
41
+ const duration = (addOptions == null ? void 0 : addOptions.duration) != null ? ms(addOptions.duration) : typeof options.duration === 'function' ? ms(options.duration(key)) : options.duration && ms(options.duration);
42
+ const threshold = (addOptions == null ? void 0 : addOptions.threshold) || typeof options.threshold && (typeof options.threshold === 'function' ? options.threshold(key) : options.threshold);
43
+ assert(duration != null || threshold != null, '参数 threshold 和 duration 必须至少设置 1 个');
37
44
  const redisKey = !key ? redisKeyPrefix : `${redisKeyPrefix}_${key}`;
38
45
  const res = await x.redis.multi([['llen', redisKey], ['lpush', redisKey, JSON.stringify(data)]]).exec();
46
+ const count = parseInt(res[0][1], 10) + 1; // 时段与阈值并存
47
+ // 满10条推送,若超过1分钟仍未满10条,则亦推送
39
48
 
40
- if (parseInt(res[0][1], 10) === 0) {
49
+ if (duration != null && threshold != null) {
50
+ const delayTaskId = redisKey;
51
+ await task.getJob(delayTaskId).then(job => job == null ? void 0 : job.remove());
41
52
  await task.add({
42
53
  key: key,
43
54
  redisKey: redisKey
44
55
  }, {
45
- delay: (addOptions == null ? void 0 : addOptions.duration) != null ? ms(addOptions.duration) : typeof options.duration === 'function' ? ms(options.duration(key)) : ms(options.duration)
56
+ jobId: delayTaskId,
57
+ delay: duration
46
58
  });
59
+
60
+ if (count === threshold) {
61
+ await task.add({
62
+ key: key,
63
+ redisKey: redisKey,
64
+ count: threshold
65
+ });
66
+ }
67
+ } // 仅时段
68
+ // 1分钟内的合并推送
69
+ else if (duration != null) {
70
+ if (count === 1) {
71
+ await task.add({
72
+ key: key,
73
+ redisKey: redisKey
74
+ }, {
75
+ delay: duration
76
+ });
77
+ }
78
+ } // 仅阈值
79
+ // 满10条推送
80
+ else if (threshold != null) {
81
+ if (count === threshold) {
82
+ await task.add({
83
+ key: key,
84
+ redisKey: redisKey,
85
+ count: threshold
86
+ });
87
+ }
47
88
  }
48
89
  }
49
90
  };
@@ -157,7 +157,7 @@ export declare namespace XTask {
157
157
  }
158
158
  interface Task<T> extends Queue<T> {
159
159
  }
160
- interface SliceTaskOptions<T, K> {
160
+ type SliceTaskOptions<T, K> = {
161
161
  /**
162
162
  * 任务名称
163
163
  */
@@ -165,21 +165,27 @@ export declare namespace XTask {
165
165
  /**
166
166
  * 持续时长
167
167
  */
168
- duration: MsValue | ((key: K) => MsValue);
168
+ duration?: MsValue | ((key: K) => MsValue);
169
+ /**
170
+ * 阈值数量
171
+ */
172
+ threshold?: number | ((key: K) => number);
169
173
  /**
170
174
  * 处理器
171
175
  */
172
176
  handle: (data: T[], key: K) => any;
173
- }
177
+ };
174
178
  interface SliceTaskNoKey<T> {
175
179
  add: (data: T, options?: {
176
180
  duration?: MsValue;
181
+ threshold?: number;
177
182
  }) => Promise<void>;
178
183
  }
179
184
  interface SliceTask<T, K> {
180
185
  add: (data: T, options: {
181
186
  key: K;
182
187
  duration?: MsValue;
188
+ threshold?: number;
183
189
  }) => Promise<void>;
184
190
  }
185
191
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jayfong/x-server",
3
- "version": "1.35.2",
3
+ "version": "1.35.4",
4
4
  "license": "ISC",
5
5
  "sideEffects": false,
6
6
  "main": "lib/_cjs/index.js",
@@ -71,7 +71,7 @@
71
71
  "ts-morph": "^12.2.0",
72
72
  "utf-8-validate": "^5.0.9",
73
73
  "vscode-generate-index-standalone": "^1.6.0",
74
- "vtils": "^4.60.0",
74
+ "vtils": "^4.67.0",
75
75
  "yargs": "^17.4.1"
76
76
  },
77
77
  "devDependencies": {