koatty_store 1.7.0 → 1.8.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/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * @Author: richen
3
- * @Date: 2024-11-07 14:38:56
3
+ * @Date: 2025-06-09 12:32:48
4
4
  * @License: BSD (3-Clause)
5
5
  * @Copyright (c) - <richenlin(at)gmail.com>
6
6
  * @HomePage: https://koatty.org/
@@ -8,6 +8,7 @@
8
8
  import { flatten, isNil, union, isUndefined } from 'lodash';
9
9
  import * as helper from 'koatty_lib';
10
10
  import { EventEmitter } from 'events';
11
+ import { LRUCache } from 'lru-cache';
11
12
  import { DefaultLogger } from 'koatty_logger';
12
13
  import { Cluster, Redis } from 'ioredis';
13
14
  import genericPool from 'generic-pool';
@@ -49,7 +50,7 @@ var messages;
49
50
  messages["mutuallyExclusiveNXXX"] = "ERR XX and NX options at the same time are not compatible";
50
51
  })(messages || (messages = {}));
51
52
  class MemoryCache extends EventEmitter {
52
- databases = Object.create({});
53
+ databases = new Map();
53
54
  options;
54
55
  currentDBIndex;
55
56
  connected;
@@ -57,18 +58,89 @@ class MemoryCache extends EventEmitter {
57
58
  multiMode;
58
59
  cache;
59
60
  responseMessages;
61
+ ttlCheckTimer = null;
60
62
  /**
61
63
  * Creates an instance of MemoryCache.
62
- * @param {*} options
64
+ * @param {MemoryCacheOptions} options
63
65
  * @memberof MemoryCache
64
66
  */
65
67
  constructor(options) {
66
68
  super();
67
- this.options = { ...{ database: "0" }, ...options };
68
- this.currentDBIndex = 0;
69
+ this.options = {
70
+ database: 0,
71
+ maxKeys: 1000,
72
+ evictionPolicy: 'lru',
73
+ ttlCheckInterval: 60000, // 1分钟检查一次过期键
74
+ maxAge: 1000 * 60 * 60, // 默认1小时过期
75
+ ...options
76
+ };
77
+ this.currentDBIndex = options.database || 0;
69
78
  this.connected = false;
70
79
  this.lastSave = Date.now();
71
80
  this.multiMode = false;
81
+ this.responseMessages = [];
82
+ // 初始化数据库和缓存
83
+ if (!this.databases.has(this.currentDBIndex)) {
84
+ this.databases.set(this.currentDBIndex, this.createLRUCache());
85
+ }
86
+ this.cache = this.databases.get(this.currentDBIndex);
87
+ // 启动TTL检查定时器
88
+ this.startTTLCheck();
89
+ }
90
+ /**
91
+ * 创建LRU缓存实例
92
+ */
93
+ createLRUCache() {
94
+ return new LRUCache({
95
+ max: this.options.maxKeys || 1000,
96
+ ttl: this.options.maxAge || 1000 * 60 * 60, // 1小时默认
97
+ updateAgeOnGet: true, // 访问时更新age
98
+ dispose: (value, key, reason) => {
99
+ // 键被淘汰时的回调 - 直接使用lru-cache的事件机制
100
+ this.emit('evict', key, value, reason);
101
+ },
102
+ onInsert: (value, key) => {
103
+ // 键被插入时的回调
104
+ this.emit('insert', key, value);
105
+ }
106
+ });
107
+ }
108
+ /**
109
+ * 启动TTL检查定时器
110
+ */
111
+ startTTLCheck() {
112
+ if (this.ttlCheckTimer) {
113
+ clearInterval(this.ttlCheckTimer);
114
+ }
115
+ this.ttlCheckTimer = setInterval(() => {
116
+ this.cleanExpiredKeys();
117
+ }, this.options.ttlCheckInterval || 60000);
118
+ }
119
+ /**
120
+ * 清理过期键
121
+ */
122
+ cleanExpiredKeys() {
123
+ for (const [_dbIndex, cache] of this.databases) {
124
+ const keysToDelete = [];
125
+ cache.forEach((item, key) => {
126
+ if (item.timeout && item.timeout <= Date.now()) {
127
+ keysToDelete.push(key);
128
+ }
129
+ });
130
+ keysToDelete.forEach(key => {
131
+ cache.delete(key);
132
+ this.emit('expire', key);
133
+ });
134
+ }
135
+ }
136
+ /**
137
+ * 停止TTL检查
138
+ */
139
+ stopTTLCheck() {
140
+ if (this.ttlCheckTimer) {
141
+ clearInterval(this.ttlCheckTimer);
142
+ this.ttlCheckTimer = null;
143
+ }
72
144
  }
73
145
  /**
74
146
  *
@@ -77,8 +149,10 @@ class MemoryCache extends EventEmitter {
77
149
  * @memberof MemoryCache
78
150
  */
79
151
  createClient() {
80
- this.databases[this.options.database] = Object.create({});
81
- this.cache = this.databases[this.options.database];
152
+ if (!this.databases.has(this.options.database)) {
153
+ this.databases.set(this.options.database, this.createLRUCache());
154
+ }
155
+ this.cache = this.databases.get(this.options.database);
82
156
  this.connected = true;
83
157
  // exit multi mode if we are in it
84
158
  this.discard(null, true);
@@ -94,6 +168,7 @@ class MemoryCache extends EventEmitter {
94
168
  */
95
169
  quit() {
96
170
  this.connected = false;
171
+ this.stopTTLCheck();
97
172
  // exit multi mode if we are in it
98
173
  this.discard(null, true);
99
174
  this.emit('end');
@@ -108,6 +183,40 @@ class MemoryCache extends EventEmitter {
108
183
  end() {
109
184
  return this.quit();
110
185
  }
186
+ /**
187
+ * 获取缓存统计信息
188
+ */
189
+ info() {
190
+ const stats = {
191
+ databases: this.databases.size,
192
+ currentDB: this.currentDBIndex,
193
+ keys: this.cache ? this.cache.length : 0,
194
+ maxKeys: this.options.maxKeys,
195
+ hits: 0,
196
+ misses: 0,
197
+ memory: this.getMemoryUsage()
198
+ };
199
+ // 如果缓存支持统计信息
200
+ if (this.cache && typeof this.cache.dump === 'function') {
201
+ const dump = this.cache.dump();
202
+ stats.keys = dump.length;
203
+ }
204
+ return stats;
205
+ }
206
+ /**
207
+ * 估算内存使用量
208
+ */
209
+ getMemoryUsage() {
210
+ let totalSize = 0;
211
+ for (const [, cache] of this.databases) {
212
+ cache.forEach((item, key) => {
213
+ // 粗略估算:key长度 + JSON序列化后的大小
214
+ totalSize += key.length * 2; // Unicode字符占2字节
215
+ totalSize += JSON.stringify(item).length * 2;
216
+ });
217
+ }
218
+ return totalSize;
219
+ }
111
220
  /**
112
221
  *
113
222
  *
@@ -154,12 +263,12 @@ class MemoryCache extends EventEmitter {
154
263
  if (!helper.isNumber(dbIndex)) {
155
264
  return this._handleCallback(callback, null, messages.invalidDBIndex);
156
265
  }
157
- if (!this.databases.hasOwnProperty(dbIndex)) {
158
- this.databases[dbIndex] = Object.create({});
266
+ if (!this.databases.has(dbIndex)) {
267
+ this.databases.set(dbIndex, this.createLRUCache());
159
268
  }
160
269
  this.multiMode = false;
161
270
  this.currentDBIndex = dbIndex;
162
- this.cache = this.databases[dbIndex];
271
+ this.cache = this.databases.get(dbIndex);
163
272
  return this._handleCallback(callback, messages.ok);
164
273
  }
165
274
  // ---------------------------------------
@@ -238,7 +347,7 @@ class MemoryCache extends EventEmitter {
238
347
  else if (onlyexist) {
239
348
  return this._handleCallback(callback, retVal);
240
349
  }
241
- this.cache[key] = this._makeKey(value.toString(), 'string', pttl);
350
+ this.cache.set(key, this._makeKey(value.toString(), 'string', pttl));
242
351
  return this._handleCallback(callback, messages.ok);
243
352
  }
244
353
  /**
@@ -268,7 +377,8 @@ class MemoryCache extends EventEmitter {
268
377
  expire(key, seconds, callback) {
269
378
  let retVal = 0;
270
379
  if (this._hasKey(key)) {
271
- this.cache[key].timeout = Date.now() + seconds * 1000;
380
+ const pttl = seconds * 1000;
381
+ this.cache.set(key, { ...this.cache.get(key), timeout: Date.now() + pttl });
272
382
  retVal = 1;
273
383
  }
274
384
  return this._handleCallback(callback, retVal);
@@ -288,7 +398,7 @@ class MemoryCache extends EventEmitter {
288
398
  for (let itr = 0; itr < keys.length; itr++) {
289
399
  const key = keys[itr];
290
400
  if (this._hasKey(key)) {
291
- delete this.cache[key];
401
+ this.cache.delete(key);
292
402
  retVal++;
293
403
  }
294
404
  }
@@ -379,7 +489,7 @@ class MemoryCache extends EventEmitter {
379
489
  decrby(key, amount, callback) {
380
490
  let retVal = null;
381
491
  try {
382
- retVal = this._addToKey(key, -amount);
492
+ retVal = this._addToKey(key, 0 - amount);
383
493
  }
384
494
  catch (err) {
385
495
  return this._handleCallback(callback, null, err);
@@ -395,7 +505,7 @@ class MemoryCache extends EventEmitter {
395
505
  this._testType(key, 'hash', true, callback);
396
506
  }
397
507
  else {
398
- this.cache[key] = this._makeKey({}, 'hash');
508
+ this.cache.set(key, this._makeKey({}, 'hash'));
399
509
  }
400
510
  if (!this._hasField(key, field)) {
401
511
  retVal = 1;
@@ -458,7 +568,7 @@ class MemoryCache extends EventEmitter {
458
568
  for (let itr = 0; itr < fields.length; itr++) {
459
569
  const field = fields[itr];
460
570
  if (this._hasField(key, field)) {
461
- delete this.cache[key].value[field];
571
+ delete this.cache.get(key).value[field];
462
572
  retVal++;
463
573
  }
464
574
  }
@@ -579,22 +689,18 @@ class MemoryCache extends EventEmitter {
579
689
  this._testType(key, 'list', true, callback);
580
690
  }
581
691
  else {
582
- this.cache[key] = this._makeKey([], 'list');
692
+ this.cache.set(key, this._makeKey([], 'list'));
583
693
  }
584
- const val = this._getKey(key);
585
- val.push(value);
586
- this._setKey(key, val);
587
- retVal = val.length;
694
+ this._getKey(key).push(value.toString());
695
+ retVal = this._getKey(key).length;
696
+ this.persist(key);
588
697
  return this._handleCallback(callback, retVal);
589
698
  }
590
699
  /**
591
- *
592
- *
593
- * @param {string} key
594
- * @param {(string | number)} value
595
- * @param {Function} [callback]
596
- * @returns {*}
597
- * @memberof MemoryCache
700
+ * List:从左侧推入
701
+ * @param key
702
+ * @param value
703
+ * @param callback
598
704
  */
599
705
  lpush(key, value, callback) {
600
706
  let retVal = 0;
@@ -602,14 +708,31 @@ class MemoryCache extends EventEmitter {
602
708
  this._testType(key, 'list', true, callback);
603
709
  }
604
710
  else {
605
- this.cache[key] = this._makeKey([], 'list');
711
+ this.cache.set(key, this._makeKey([], 'list'));
606
712
  }
607
- const val = this._getKey(key);
608
- val.splice(0, 0, value);
609
- this._setKey(key, val);
610
- retVal = val.length;
713
+ const list = this._getKey(key);
714
+ retVal = list.unshift(value);
715
+ this._setKey(key, list);
611
716
  return this._handleCallback(callback, retVal);
612
717
  }
718
+ /**
719
+ * List:获取指定索引的元素
720
+ * @param key
721
+ * @param index
722
+ * @param callback
723
+ */
724
+ lindex(key, index, callback) {
725
+ if (!this._hasKey(key)) {
726
+ return this._handleCallback(callback, null);
727
+ }
728
+ this._testType(key, 'list', true, callback);
729
+ const list = this._getKey(key);
730
+ if (index < 0) {
731
+ index = list.length + index;
732
+ }
733
+ const value = index >= 0 && index < list.length ? list[index] : null;
734
+ return this._handleCallback(callback, value);
735
+ }
613
736
  /**
614
737
  *
615
738
  *
@@ -622,9 +745,11 @@ class MemoryCache extends EventEmitter {
622
745
  let retVal = null;
623
746
  if (this._hasKey(key)) {
624
747
  this._testType(key, 'list', true, callback);
625
- const val = this._getKey(key);
626
- retVal = val.shift();
627
- this._setKey(key, val);
748
+ const list = this._getKey(key);
749
+ if (list.length > 0) {
750
+ retVal = list.shift();
751
+ this.persist(key);
752
+ }
628
753
  }
629
754
  return this._handleCallback(callback, retVal);
630
755
  }
@@ -640,9 +765,11 @@ class MemoryCache extends EventEmitter {
640
765
  let retVal = null;
641
766
  if (this._hasKey(key)) {
642
767
  this._testType(key, 'list', true, callback);
643
- const val = this._getKey(key);
644
- retVal = val.pop();
645
- this._setKey(key, val);
768
+ const list = this._getKey(key);
769
+ if (list.length > 0) {
770
+ retVal = list.pop();
771
+ this.persist(key);
772
+ }
646
773
  }
647
774
  return this._handleCallback(callback, retVal);
648
775
  }
@@ -660,8 +787,8 @@ class MemoryCache extends EventEmitter {
660
787
  const retVal = [];
661
788
  if (this._hasKey(key)) {
662
789
  this._testType(key, 'list', true, callback);
663
- const val = this._getKey(key);
664
- const length = val.length;
790
+ const list = this._getKey(key);
791
+ const length = list.length;
665
792
  if (stop < 0) {
666
793
  stop = length + stop;
667
794
  }
@@ -677,7 +804,7 @@ class MemoryCache extends EventEmitter {
677
804
  if (stop >= 0 && stop >= start) {
678
805
  const size = stop - start + 1;
679
806
  for (let itr = start; itr < size; itr++) {
680
- retVal.push(val[itr]);
807
+ retVal.push(list[itr]);
681
808
  }
682
809
  }
683
810
  }
@@ -701,7 +828,7 @@ class MemoryCache extends EventEmitter {
701
828
  this._testType(key, 'set', true, callback);
702
829
  }
703
830
  else {
704
- this.cache[key] = this._makeKey([], 'set');
831
+ this.cache.set(key, this._makeKey([], 'set'));
705
832
  }
706
833
  const val = this._getKey(key);
707
834
  const length = val.length;
@@ -773,19 +900,29 @@ class MemoryCache extends EventEmitter {
773
900
  * @memberof MemoryCache
774
901
  */
775
902
  spop(key, count, callback) {
776
- let retVal = null;
903
+ let retVal = [];
777
904
  count = count || 1;
778
- if (isNaN(count)) {
779
- return this._handleCallback(callback, null, messages.noint);
905
+ if (typeof count === 'function') {
906
+ callback = count;
907
+ count = 1;
780
908
  }
781
909
  if (this._hasKey(key)) {
782
- retVal = [];
783
910
  this._testType(key, 'set', true, callback);
784
911
  const val = this._getKey(key);
785
- const length = val.length;
786
- count = count > length ? length : count;
787
- for (let itr = 0; itr < count; itr++) {
788
- retVal.push(val.pop());
912
+ const keys = Object.keys(val);
913
+ const keysLength = keys.length;
914
+ if (keysLength) {
915
+ if (count >= keysLength) {
916
+ retVal = keys;
917
+ this.del(key);
918
+ }
919
+ else {
920
+ for (let itr = 0; itr < count; itr++) {
921
+ const randomNum = Math.floor(Math.random() * keys.length);
922
+ retVal.push(keys[randomNum]);
923
+ this.srem(key, keys[randomNum]);
924
+ }
925
+ }
789
926
  }
790
927
  }
791
928
  return this._handleCallback(callback, retVal);
@@ -852,14 +989,14 @@ class MemoryCache extends EventEmitter {
852
989
  discard(callback, silent) {
853
990
  // Clear the queue mode, drain the queue, empty the watch list
854
991
  if (this.multiMode) {
855
- this.cache = this.databases[this.currentDBIndex];
992
+ this.cache = this.databases.get(this.currentDBIndex);
856
993
  this.multiMode = false;
857
994
  this.responseMessages = [];
858
995
  }
859
- else if (!silent) {
860
- return this._handleCallback(callback, null, messages.nomultidiscard);
996
+ if (!silent) {
997
+ return this._handleCallback(callback, messages.ok);
861
998
  }
862
- return this._handleCallback(callback, messages.ok);
999
+ return null;
863
1000
  }
864
1001
  // ---------------------------------------
865
1002
  // ## Internal - Key ##
@@ -872,11 +1009,11 @@ class MemoryCache extends EventEmitter {
872
1009
  * @returns {*}
873
1010
  * @memberof MemoryCache
874
1011
  */
875
- pttl(key, callback) {
1012
+ pttl(key, _callback) {
876
1013
  let retVal = -2;
877
1014
  if (this._hasKey(key)) {
878
- if (!isNil(this.cache[key].timeout)) {
879
- retVal = this.cache[key].timeout - Date.now();
1015
+ if (!isNil(this.cache.get(key)?.timeout)) {
1016
+ retVal = this.cache.get(key).timeout - Date.now();
880
1017
  // Prevent unexpected errors if the actual ttl just happens to be -2 or -1
881
1018
  if (retVal < 0 && retVal > -3) {
882
1019
  retVal = -3;
@@ -886,7 +1023,7 @@ class MemoryCache extends EventEmitter {
886
1023
  retVal = -1;
887
1024
  }
888
1025
  }
889
- return this._handleCallback(callback, retVal);
1026
+ return retVal;
890
1027
  }
891
1028
  /**
892
1029
  *
@@ -901,7 +1038,7 @@ class MemoryCache extends EventEmitter {
901
1038
  let retVal = 0;
902
1039
  if (this._hasKey(key)) {
903
1040
  if (!isNil(this._key(key).timeout)) {
904
- this._key(key).timeout = null;
1041
+ this.cache.set(key, { ...this.cache.get(key), timeout: null });
905
1042
  retVal = 1;
906
1043
  }
907
1044
  }
@@ -916,7 +1053,7 @@ class MemoryCache extends EventEmitter {
916
1053
  * @memberof MemoryCache
917
1054
  */
918
1055
  _hasKey(key) {
919
- return this.cache.hasOwnProperty(key);
1056
+ return this.cache.has(key);
920
1057
  }
921
1058
  /**
922
1059
  *
@@ -940,8 +1077,8 @@ class MemoryCache extends EventEmitter {
940
1077
  * @memberof MemoryCache
941
1078
  */
942
1079
  _key(key) {
943
- this.cache[key].lastAccess = Date.now();
944
- return this.cache[key];
1080
+ this.cache.get(key).lastAccess = Date.now();
1081
+ return this.cache.get(key);
945
1082
  }
946
1083
  /**
947
1084
  *
@@ -966,7 +1103,7 @@ class MemoryCache extends EventEmitter {
966
1103
  }
967
1104
  }
968
1105
  else {
969
- this.cache[key] = this._makeKey('0', 'string');
1106
+ this.cache.set(key, this._makeKey('0', 'string'));
970
1107
  }
971
1108
  const val = keyValue + amount;
972
1109
  this._setKey(key, val.toString());
@@ -1019,8 +1156,7 @@ class MemoryCache extends EventEmitter {
1019
1156
  * @memberof MemoryCache
1020
1157
  */
1021
1158
  _setKey(key, value) {
1022
- this.cache[key].value = value;
1023
- this.cache[key].lastAccess = Date.now();
1159
+ this.cache.set(key, { ...this.cache.get(key), value: value, lastAccess: Date.now() });
1024
1160
  }
1025
1161
  /**
1026
1162
  *
@@ -1048,7 +1184,7 @@ class MemoryCache extends EventEmitter {
1048
1184
  }
1049
1185
  }
1050
1186
  else {
1051
- this.cache[key] = this._makeKey({}, 'hash');
1187
+ this.cache.set(key, this._makeKey({}, 'hash'));
1052
1188
  }
1053
1189
  fieldValue = useFloat ? parseFloat(`${value}`) : parseInt(`${value}`);
1054
1190
  amount = useFloat ? parseFloat(`${amount}`) : parseInt(`${amount}`);
@@ -1157,6 +1293,333 @@ class MemoryCache extends EventEmitter {
1157
1293
  }
1158
1294
  return;
1159
1295
  }
1296
+ /**
1297
+ * 字符串追加操作
1298
+ * @param key
1299
+ * @param value
1300
+ * @param callback
1301
+ */
1302
+ append(key, value, callback) {
1303
+ let retVal = 0;
1304
+ if (this._hasKey(key)) {
1305
+ this._testType(key, 'string', true, callback);
1306
+ const existingValue = this._getKey(key);
1307
+ const newValue = existingValue + value;
1308
+ this._setKey(key, newValue);
1309
+ retVal = newValue.length;
1310
+ }
1311
+ else {
1312
+ this.cache.set(key, this._makeKey(value, 'string'));
1313
+ retVal = value.length;
1314
+ }
1315
+ return this._handleCallback(callback, retVal);
1316
+ }
1317
+ /**
1318
+ * 获取字符串长度
1319
+ * @param key
1320
+ * @param callback
1321
+ */
1322
+ strlen(key, callback) {
1323
+ let retVal = 0;
1324
+ if (this._hasKey(key)) {
1325
+ this._testType(key, 'string', true, callback);
1326
+ retVal = this._getKey(key).length;
1327
+ }
1328
+ return this._handleCallback(callback, retVal);
1329
+ }
1330
+ /**
1331
+ * 获取子字符串
1332
+ * @param key
1333
+ * @param start
1334
+ * @param end
1335
+ * @param callback
1336
+ */
1337
+ getrange(key, start, end, callback) {
1338
+ let retVal = '';
1339
+ if (this._hasKey(key)) {
1340
+ this._testType(key, 'string', true, callback);
1341
+ const value = this._getKey(key);
1342
+ retVal = value.substring(start, end + 1);
1343
+ }
1344
+ return this._handleCallback(callback, retVal);
1345
+ }
1346
+ /**
1347
+ * 设置子字符串
1348
+ * @param key
1349
+ * @param offset
1350
+ * @param value
1351
+ * @param callback
1352
+ */
1353
+ setrange(key, offset, value, callback) {
1354
+ let retVal = 0;
1355
+ if (this._hasKey(key)) {
1356
+ this._testType(key, 'string', true, callback);
1357
+ const existingValue = this._getKey(key);
1358
+ const newValue = existingValue.substring(0, offset) + value + existingValue.substring(offset + value.length);
1359
+ this._setKey(key, newValue);
1360
+ retVal = newValue.length;
1361
+ }
1362
+ else {
1363
+ // 如果键不存在,创建一个足够长的字符串
1364
+ const newValue = ''.padEnd(offset, '\0') + value;
1365
+ this.cache.set(key, this._makeKey(newValue, 'string'));
1366
+ retVal = newValue.length;
1367
+ }
1368
+ return this._handleCallback(callback, retVal);
1369
+ }
1370
+ /**
1371
+ * 批量获取
1372
+ * @param keys
1373
+ * @param callback
1374
+ */
1375
+ mget(...keys) {
1376
+ const callback = this._retrieveCallback(keys);
1377
+ const retVal = [];
1378
+ for (const key of keys) {
1379
+ if (this._hasKey(key)) {
1380
+ this._testType(key, 'string', false, callback);
1381
+ retVal.push(this._getKey(key));
1382
+ }
1383
+ else {
1384
+ retVal.push(null);
1385
+ }
1386
+ }
1387
+ return this._handleCallback(callback, retVal);
1388
+ }
1389
+ /**
1390
+ * 批量设置
1391
+ * @param keyValuePairs
1392
+ * @param callback
1393
+ */
1394
+ mset(...keyValuePairs) {
1395
+ const callback = this._retrieveCallback(keyValuePairs);
1396
+ // 确保参数是偶数个
1397
+ if (keyValuePairs.length % 2 !== 0) {
1398
+ return this._handleCallback(callback, null, messages.wrongArgCount.replace('%0', 'mset'));
1399
+ }
1400
+ for (let i = 0; i < keyValuePairs.length; i += 2) {
1401
+ const key = keyValuePairs[i];
1402
+ const value = keyValuePairs[i + 1];
1403
+ this.cache.set(key, this._makeKey(value.toString(), 'string'));
1404
+ }
1405
+ return this._handleCallback(callback, messages.ok);
1406
+ }
1407
+ /**
1408
+ * 获取所有键
1409
+ * @param pattern
1410
+ * @param callback
1411
+ */
1412
+ keys(pattern = '*', callback) {
1413
+ const retVal = [];
1414
+ this.cache.forEach((_item, key) => {
1415
+ if (pattern === '*' || this.matchPattern(key, pattern)) {
1416
+ retVal.push(key);
1417
+ }
1418
+ });
1419
+ return this._handleCallback(callback, retVal);
1420
+ }
1421
+ /**
1422
+ * 简单的模式匹配
1423
+ * @param key
1424
+ * @param pattern
1425
+ */
1426
+ matchPattern(key, pattern) {
1427
+ if (pattern === '*')
1428
+ return true;
1429
+ // 转换glob模式为正则表达式
1430
+ const regexPattern = pattern
1431
+ .replace(/\*/g, '.*')
1432
+ .replace(/\?/g, '.')
1433
+ .replace(/\[([^\]]*)\]/g, '[$1]');
1434
+ const regex = new RegExp(`^${regexPattern}$`);
1435
+ return regex.test(key);
1436
+ }
1437
+ /**
1438
+ * 获取随机键
1439
+ * @param callback
1440
+ */
1441
+ randomkey(callback) {
1442
+ const keys = [];
1443
+ this.cache.forEach((_item, key) => {
1444
+ keys.push(key);
1445
+ });
1446
+ if (keys.length === 0) {
1447
+ return this._handleCallback(callback, null);
1448
+ }
1449
+ const randomIndex = Math.floor(Math.random() * keys.length);
1450
+ return this._handleCallback(callback, keys[randomIndex]);
1451
+ }
1452
+ /**
1453
+ * 重命名键
1454
+ * @param oldKey
1455
+ * @param newKey
1456
+ * @param callback
1457
+ */
1458
+ rename(oldKey, newKey, callback) {
1459
+ if (!this._hasKey(oldKey)) {
1460
+ return this._handleCallback(callback, null, messages.nokey);
1461
+ }
1462
+ const value = this.cache.get(oldKey);
1463
+ this.cache.set(newKey, value);
1464
+ this.cache.delete(oldKey);
1465
+ return this._handleCallback(callback, messages.ok);
1466
+ }
1467
+ /**
1468
+ * 安全重命名键(目标键不存在时才重命名)
1469
+ * @param oldKey
1470
+ * @param newKey
1471
+ * @param callback
1472
+ */
1473
+ renamenx(oldKey, newKey, callback) {
1474
+ if (!this._hasKey(oldKey)) {
1475
+ return this._handleCallback(callback, null, messages.nokey);
1476
+ }
1477
+ if (this._hasKey(newKey)) {
1478
+ return this._handleCallback(callback, 0);
1479
+ }
1480
+ const value = this.cache.get(oldKey);
1481
+ this.cache.set(newKey, value);
1482
+ this.cache.delete(oldKey);
1483
+ return this._handleCallback(callback, 1);
1484
+ }
1485
+ /**
1486
+ * 获取键的类型
1487
+ * @param key
1488
+ * @param callback
1489
+ */
1490
+ type(key, callback) {
1491
+ if (!this._hasKey(key)) {
1492
+ return this._handleCallback(callback, 'none');
1493
+ }
1494
+ const item = this.cache.get(key);
1495
+ return this._handleCallback(callback, item.type);
1496
+ }
1497
+ /**
1498
+ * 清空当前数据库
1499
+ * @param callback
1500
+ */
1501
+ flushdb(callback) {
1502
+ this.cache.clear();
1503
+ return this._handleCallback(callback, messages.ok);
1504
+ }
1505
+ /**
1506
+ * 清空所有数据库
1507
+ * @param callback
1508
+ */
1509
+ flushall(callback) {
1510
+ this.databases.clear();
1511
+ this.cache = this.createLRUCache();
1512
+ this.databases.set(this.currentDBIndex, this.cache);
1513
+ return this._handleCallback(callback, messages.ok);
1514
+ }
1515
+ /**
1516
+ * 获取数据库大小
1517
+ * @param callback
1518
+ */
1519
+ dbsize(callback) {
1520
+ const size = this.cache.size || 0;
1521
+ return this._handleCallback(callback, size);
1522
+ }
1523
+ /**
1524
+ * Sorted Set基础实现 - 添加成员
1525
+ * @param key
1526
+ * @param score
1527
+ * @param member
1528
+ * @param callback
1529
+ */
1530
+ zadd(key, score, member, callback) {
1531
+ let retVal = 0;
1532
+ if (this._hasKey(key)) {
1533
+ this._testType(key, 'zset', true, callback);
1534
+ }
1535
+ else {
1536
+ this.cache.set(key, this._makeKey([], 'zset'));
1537
+ }
1538
+ const zset = this._getKey(key);
1539
+ const existing = zset.find((item) => item.member === member);
1540
+ if (existing) {
1541
+ existing.score = score;
1542
+ }
1543
+ else {
1544
+ zset.push({ score, member });
1545
+ retVal = 1;
1546
+ }
1547
+ // 按分数排序
1548
+ zset.sort((a, b) => a.score - b.score);
1549
+ this._setKey(key, zset);
1550
+ return this._handleCallback(callback, retVal);
1551
+ }
1552
+ /**
1553
+ * Sorted Set - 获取成员分数
1554
+ * @param key
1555
+ * @param member
1556
+ * @param callback
1557
+ */
1558
+ zscore(key, member, callback) {
1559
+ if (!this._hasKey(key)) {
1560
+ return this._handleCallback(callback, null);
1561
+ }
1562
+ this._testType(key, 'zset', true, callback);
1563
+ const zset = this._getKey(key);
1564
+ const item = zset.find((item) => item.member === member);
1565
+ return this._handleCallback(callback, item ? item.score : null);
1566
+ }
1567
+ /**
1568
+ * Sorted Set - 获取范围内的成员
1569
+ * @param key
1570
+ * @param start
1571
+ * @param stop
1572
+ * @param callback
1573
+ */
1574
+ zrange(key, start, stop, callback) {
1575
+ if (!this._hasKey(key)) {
1576
+ return this._handleCallback(callback, []);
1577
+ }
1578
+ this._testType(key, 'zset', true, callback);
1579
+ const zset = this._getKey(key);
1580
+ const length = zset.length;
1581
+ if (stop < 0) {
1582
+ stop = length + stop;
1583
+ }
1584
+ if (start < 0) {
1585
+ start = length + start;
1586
+ }
1587
+ const retVal = zset.slice(start, stop + 1).map((item) => item.member);
1588
+ return this._handleCallback(callback, retVal);
1589
+ }
1590
+ /**
1591
+ * Sorted Set - 获取成员数量
1592
+ * @param key
1593
+ * @param callback
1594
+ */
1595
+ zcard(key, callback) {
1596
+ if (!this._hasKey(key)) {
1597
+ return this._handleCallback(callback, 0);
1598
+ }
1599
+ this._testType(key, 'zset', true, callback);
1600
+ const zset = this._getKey(key);
1601
+ return this._handleCallback(callback, zset.length);
1602
+ }
1603
+ /**
1604
+ * Sorted Set - 删除成员
1605
+ * @param key
1606
+ * @param member
1607
+ * @param callback
1608
+ */
1609
+ zrem(key, member, callback) {
1610
+ let retVal = 0;
1611
+ if (this._hasKey(key)) {
1612
+ this._testType(key, 'zset', true, callback);
1613
+ const zset = this._getKey(key);
1614
+ const index = zset.findIndex((item) => item.member === member);
1615
+ if (index !== -1) {
1616
+ zset.splice(index, 1);
1617
+ retVal = 1;
1618
+ this._setKey(key, zset);
1619
+ }
1620
+ }
1621
+ return this._handleCallback(callback, retVal);
1622
+ }
1160
1623
  }
1161
1624
 
1162
1625
  /*
@@ -1176,7 +1639,12 @@ class MemoryStore {
1176
1639
  * @memberof MemoryStore
1177
1640
  */
1178
1641
  constructor(options) {
1179
- this.options = options;
1642
+ this.options = {
1643
+ maxKeys: 1000,
1644
+ evictionPolicy: 'lru',
1645
+ ttlCheckInterval: 60000, // 1分钟
1646
+ ...options
1647
+ };
1180
1648
  this.client = null;
1181
1649
  }
1182
1650
  /**
@@ -1188,7 +1656,11 @@ class MemoryStore {
1188
1656
  getConnection() {
1189
1657
  if (!this.pool) {
1190
1658
  this.pool = new MemoryCache({
1191
- database: this.options.db
1659
+ database: this.options.db || 0,
1660
+ maxKeys: this.options.maxKeys,
1661
+ maxMemory: this.options.maxMemory,
1662
+ evictionPolicy: this.options.evictionPolicy,
1663
+ ttlCheckInterval: this.options.ttlCheckInterval
1192
1664
  });
1193
1665
  }
1194
1666
  if (!this.client) {
@@ -1204,8 +1676,10 @@ class MemoryStore {
1204
1676
  * @memberof MemoryStore
1205
1677
  */
1206
1678
  async close() {
1207
- this.client.end();
1208
- this.client = null;
1679
+ if (this.client) {
1680
+ this.client.end();
1681
+ this.client = null;
1682
+ }
1209
1683
  }
1210
1684
  /**
1211
1685
  * release
@@ -1248,6 +1722,20 @@ class MemoryStore {
1248
1722
  return -1;
1249
1723
  }
1250
1724
  }
1725
+ /**
1726
+ * 获取缓存统计信息
1727
+ */
1728
+ getStats() {
1729
+ if (this.client) {
1730
+ return this.client.info();
1731
+ }
1732
+ return {
1733
+ keys: 0,
1734
+ memory: 0,
1735
+ hits: 0,
1736
+ misses: 0
1737
+ };
1738
+ }
1251
1739
  }
1252
1740
 
1253
1741
  /*
@@ -1268,6 +1756,9 @@ class RedisStore {
1268
1756
  options;
1269
1757
  pool;
1270
1758
  client;
1759
+ reconnectAttempts = 0;
1760
+ maxReconnectAttempts = 5;
1761
+ reconnectDelay = 1000; // 初始重连延迟1秒
1271
1762
  /**
1272
1763
  * Creates an instance of RedisStore.
1273
1764
  * @param {RedisStoreOpt} options
@@ -1327,7 +1818,7 @@ class RedisStore {
1327
1818
  return opt;
1328
1819
  }
1329
1820
  /**
1330
- * create connection by native
1821
+ * create connection by native with improved error handling
1331
1822
  *
1332
1823
  * @param {number} [connNum=0]
1333
1824
  * @returns {*} {Promise<Redis | Cluster>}
@@ -1339,32 +1830,77 @@ class RedisStore {
1339
1830
  }
1340
1831
  const defer = helper.getDefer();
1341
1832
  let connection;
1342
- if (!helper.isEmpty(this.options.clusters)) {
1343
- connection = new Cluster([...this.options.clusters], { redisOptions: this.options });
1344
- }
1345
- else {
1346
- connection = new Redis(this.options);
1347
- }
1348
- // 去除prefix, 防止重复
1349
- this.options.keyPrefix = "";
1350
- connection.on('end', () => {
1351
- if (connNum < 3) {
1352
- connNum++;
1353
- defer.resolve(this.connect(connNum));
1833
+ try {
1834
+ if (!helper.isEmpty(this.options.clusters)) {
1835
+ connection = new Cluster([...this.options.clusters], {
1836
+ redisOptions: this.options,
1837
+ enableOfflineQueue: false,
1838
+ retryDelayOnFailover: 100
1839
+ });
1354
1840
  }
1355
1841
  else {
1356
- this.close();
1357
- defer.reject('redis connection end');
1842
+ connection = new Redis({
1843
+ ...this.options,
1844
+ enableOfflineQueue: false,
1845
+ retryDelayOnFailover: 100,
1846
+ lazyConnect: true
1847
+ });
1358
1848
  }
1359
- });
1360
- connection.on('ready', () => {
1361
- this.client = connection;
1362
- defer.resolve(connection);
1363
- });
1849
+ // 去除prefix, 防止重复
1850
+ this.options.keyPrefix = "";
1851
+ connection.on('error', (err) => {
1852
+ DefaultLogger.Error(`Redis connection error: ${err.message}`);
1853
+ if (this.reconnectAttempts < this.maxReconnectAttempts) {
1854
+ this.scheduleReconnect(connNum);
1855
+ }
1856
+ else {
1857
+ defer.reject(new Error(`Redis connection failed after ${this.maxReconnectAttempts} attempts`));
1858
+ }
1859
+ });
1860
+ connection.on('end', () => {
1861
+ DefaultLogger.Warn('Redis connection ended');
1862
+ if (connNum < 3) {
1863
+ this.scheduleReconnect(connNum + 1);
1864
+ }
1865
+ else {
1866
+ this.close();
1867
+ defer.reject(new Error('Redis connection end after 3 attempts'));
1868
+ }
1869
+ });
1870
+ connection.on('ready', () => {
1871
+ DefaultLogger.Info('Redis connection ready');
1872
+ this.client = connection;
1873
+ this.reconnectAttempts = 0; // 重置重连计数
1874
+ defer.resolve(connection);
1875
+ });
1876
+ // 主动连接
1877
+ if (connection instanceof Redis) {
1878
+ await connection.connect();
1879
+ }
1880
+ }
1881
+ catch (error) {
1882
+ DefaultLogger.Error(`Failed to create Redis connection: ${error.message}`);
1883
+ defer.reject(error);
1884
+ }
1364
1885
  return defer.promise;
1365
1886
  }
1366
1887
  /**
1367
- * get connection from pool
1888
+ * 计划重连,使用指数退避策略
1889
+ * @private
1890
+ * @param {number} connNum
1891
+ */
1892
+ scheduleReconnect(connNum) {
1893
+ this.reconnectAttempts++;
1894
+ const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1);
1895
+ DefaultLogger.Info(`Scheduling Redis reconnect attempt ${this.reconnectAttempts} in ${delay}ms`);
1896
+ setTimeout(() => {
1897
+ this.connect(connNum).catch(err => {
1898
+ DefaultLogger.Error(`Reconnect attempt ${this.reconnectAttempts} failed: ${err.message}`);
1899
+ });
1900
+ }, delay);
1901
+ }
1902
+ /**
1903
+ * get connection from pool with improved configuration
1368
1904
  *
1369
1905
  * @returns {*}
1370
1906
  * @memberof RedisStore
@@ -1375,38 +1911,57 @@ class RedisStore {
1375
1911
  create: () => {
1376
1912
  return this.connect();
1377
1913
  },
1378
- destroy: () => {
1379
- return this.close();
1914
+ destroy: (resource) => {
1915
+ if (resource && typeof resource.disconnect === 'function') {
1916
+ resource.disconnect();
1917
+ }
1918
+ return Promise.resolve();
1380
1919
  },
1381
1920
  validate: (resource) => {
1382
- return Promise.resolve(resource.status === 'ready');
1921
+ return Promise.resolve(resource && resource.status === 'ready');
1383
1922
  }
1384
1923
  };
1385
1924
  this.pool = genericPool.createPool(factory, {
1386
1925
  max: this.options.poolSize || 10, // maximum size of the pool
1387
- min: 2 // minimum size of the pool
1926
+ min: Math.min(2, this.options.poolSize || 2), // minimum size of the pool
1927
+ acquireTimeoutMillis: 30000, // 30秒获取连接超时
1928
+ testOnBorrow: true, // 借用时测试连接
1929
+ evictionRunIntervalMillis: 30000, // 30秒检查一次空闲连接
1930
+ idleTimeoutMillis: 300000, // 5分钟空闲超时
1931
+ softIdleTimeoutMillis: 180000 // 3分钟软空闲超时
1388
1932
  });
1389
1933
  this.pool.on('factoryCreateError', function (err) {
1390
- DefaultLogger.Error(err);
1934
+ DefaultLogger.Error(`Redis pool create error: ${err.message}`);
1391
1935
  });
1392
1936
  this.pool.on('factoryDestroyError', function (err) {
1393
- DefaultLogger.Error(err);
1937
+ DefaultLogger.Error(`Redis pool destroy error: ${err.message}`);
1394
1938
  });
1395
1939
  }
1396
1940
  return this.pool.acquire();
1397
1941
  }
1398
1942
  /**
1399
- * close connection
1943
+ * close connection with proper cleanup
1400
1944
  *
1401
1945
  * @returns {*}
1402
1946
  * @memberof RedisStore
1403
1947
  */
1404
1948
  async close() {
1405
- this.client.disconnect();
1406
- this.client = null;
1407
- this.pool.destroy(this.client);
1408
- this.pool = null;
1409
- return;
1949
+ try {
1950
+ if (this.pool) {
1951
+ await this.pool.drain();
1952
+ await this.pool.clear();
1953
+ this.pool = null;
1954
+ }
1955
+ if (this.client) {
1956
+ if (typeof this.client.disconnect === 'function') {
1957
+ this.client.disconnect();
1958
+ }
1959
+ this.client = null;
1960
+ }
1961
+ }
1962
+ catch (error) {
1963
+ DefaultLogger.Error(`Error closing Redis connection: ${error.message}`);
1964
+ }
1410
1965
  }
1411
1966
  /**
1412
1967
  *
@@ -1449,16 +2004,16 @@ class RedisStore {
1449
2004
  try {
1450
2005
  conn = await this.defineCommand("getCompare", {
1451
2006
  numberOfKeys: 1,
1452
- lua: `
1453
- local remote_value = redis.call("get",KEYS[1])
1454
-
1455
- if (not remote_value) then
1456
- return 0
1457
- elseif (remote_value == ARGV[1]) then
1458
- return redis.call("del",KEYS[1])
1459
- else
1460
- return -1
1461
- end
2007
+ lua: `
2008
+ local remote_value = redis.call("get",KEYS[1])
2009
+
2010
+ if (not remote_value) then
2011
+ return 0
2012
+ elseif (remote_value == ARGV[1]) then
2013
+ return redis.call("del",KEYS[1])
2014
+ else
2015
+ return -1
2016
+ end
1462
2017
  `
1463
2018
  });
1464
2019
  return conn.getCompare(name, value);
@@ -1498,7 +2053,7 @@ const defaultOptions = {
1498
2053
  class CacheStore {
1499
2054
  client;
1500
2055
  options;
1501
- static instance;
2056
+ static instances = new Map();
1502
2057
  /**
1503
2058
  * Creates an instance of CacheStore.
1504
2059
  * @param {StoreOptions} options
@@ -1518,17 +2073,70 @@ class CacheStore {
1518
2073
  }
1519
2074
  }
1520
2075
  /**
1521
- *
1522
- *
2076
+ * 获取单例实例,支持多配置实例管理
1523
2077
  * @static
1524
- * @returns
2078
+ * @param {StoreOptions} [options]
2079
+ * @param {string} [instanceKey='default'] 实例键名,用于区分不同配置的实例
2080
+ * @returns {CacheStore}
2081
+ */
2082
+ static getInstance(options, instanceKey = 'default') {
2083
+ // 生成配置哈希作为实例键的一部分
2084
+ const configHash = options ? this.generateConfigHash(options) : 'default';
2085
+ const fullKey = `${instanceKey}_${configHash}`;
2086
+ if (this.instances.has(fullKey)) {
2087
+ return this.instances.get(fullKey);
2088
+ }
2089
+ const instance = new CacheStore(options);
2090
+ this.instances.set(fullKey, instance);
2091
+ return instance;
2092
+ }
2093
+ /**
2094
+ * 生成配置哈希
2095
+ * @private
2096
+ * @static
2097
+ * @param {StoreOptions} options
2098
+ * @returns {string}
1525
2099
  */
1526
- static getInstance(options) {
1527
- if (this.instance) {
1528
- return this.instance;
2100
+ static generateConfigHash(options) {
2101
+ const configStr = JSON.stringify({
2102
+ type: options.type,
2103
+ host: options.host,
2104
+ port: options.port,
2105
+ db: options.db,
2106
+ keyPrefix: options.keyPrefix
2107
+ });
2108
+ // 简单哈希函数
2109
+ let hash = 0;
2110
+ for (let i = 0; i < configStr.length; i++) {
2111
+ const char = configStr.charCodeAt(i);
2112
+ hash = ((hash << 5) - hash) + char;
2113
+ hash = hash & hash; // 转换为32位整数
1529
2114
  }
1530
- this.instance = new CacheStore(options);
1531
- return this.instance;
2115
+ return Math.abs(hash).toString(36);
2116
+ }
2117
+ /**
2118
+ * 清理指定实例
2119
+ * @static
2120
+ * @param {string} [instanceKey='default']
2121
+ */
2122
+ static async clearInstance(instanceKey = 'default') {
2123
+ const keysToRemove = Array.from(this.instances.keys()).filter(key => key.startsWith(`${instanceKey}_`));
2124
+ for (const key of keysToRemove) {
2125
+ const instance = this.instances.get(key);
2126
+ if (instance) {
2127
+ await instance.close();
2128
+ this.instances.delete(key);
2129
+ }
2130
+ }
2131
+ }
2132
+ /**
2133
+ * 清理所有实例
2134
+ * @static
2135
+ */
2136
+ static async clearAllInstances() {
2137
+ const promises = Array.from(this.instances.values()).map(instance => instance.close());
2138
+ await Promise.all(promises);
2139
+ this.instances.clear();
1532
2140
  }
1533
2141
  getConnection() {
1534
2142
  return this.client.getConnection();
@@ -1539,11 +2147,13 @@ class CacheStore {
1539
2147
  release(conn) {
1540
2148
  return this.client.release(conn);
1541
2149
  }
1542
- defineCommand(name, scripts) {
1543
- return this.client.defineCommand(name, scripts);
1544
- }
1545
- getCompare(name, value) {
1546
- return this.client.getCompare(name, value);
2150
+ /**
2151
+ * 获取底层实现客户端,用于访问特定实现的功能
2152
+ * 例如:Redis的defineCommand, getCompare等
2153
+ * @returns {MemoryStore | RedisStore}
2154
+ */
2155
+ getRawClient() {
2156
+ return this.client;
1547
2157
  }
1548
2158
  /**
1549
2159
  * handler for native client
@@ -1603,13 +2213,6 @@ class CacheStore {
1603
2213
  expire(name, timeout) {
1604
2214
  return this.wrap('expire', [`${this.options.keyPrefix || ""}${name}`, timeout]);
1605
2215
  }
1606
- /**
1607
- * 删除key
1608
- * @param name
1609
- */
1610
- rm(name) {
1611
- return this.wrap('del', [`${this.options.keyPrefix || ""}${name}`]);
1612
- }
1613
2216
  /**
1614
2217
  *
1615
2218
  *
@@ -1647,8 +2250,8 @@ class CacheStore {
1647
2250
  * @param incr
1648
2251
  * @returns {*}
1649
2252
  */
1650
- incrby(name, incr = 1) {
1651
- return this.wrap('incrby', [`${this.options.keyPrefix || ""}${name}`, incr]);
2253
+ incrby(name, increment) {
2254
+ return this.wrap('incrby', [`${this.options.keyPrefix || ""}${name}`, increment]);
1652
2255
  }
1653
2256
  /**
1654
2257
  * 将 key 所储存的值减去减量
@@ -1656,8 +2259,8 @@ class CacheStore {
1656
2259
  * @param {any} name
1657
2260
  * @param {any} decr
1658
2261
  */
1659
- decrby(name, decr = 1) {
1660
- return this.wrap('decrby', [`${this.options.keyPrefix || ""}${name}`, decr]);
2262
+ decrby(name, decrement) {
2263
+ return this.wrap('decrby', [`${this.options.keyPrefix || ""}${name}`, decrement]);
1661
2264
  }
1662
2265
  /**
1663
2266
  * 哈希写入
@@ -1666,13 +2269,16 @@ class CacheStore {
1666
2269
  * @param value
1667
2270
  * @param timeout
1668
2271
  */
1669
- hset(name, key, value, timeout) {
1670
- const setP = [this.wrap('hset', [`${this.options.keyPrefix || ""}${name}`, key, value])];
1671
- if (typeof timeout !== 'number') {
1672
- timeout = this.options.timeout;
2272
+ async hset(name, key, value, timeout) {
2273
+ const result = await this.wrap('hset', [`${this.options.keyPrefix || ""}${name}`, key, value]);
2274
+ if (typeof timeout === 'number') {
2275
+ await this.set(`${name}:${key}_ex`, 1, timeout);
1673
2276
  }
1674
- setP.push(this.set(`${name}:${key}_ex`, 1, timeout));
1675
- return Promise.all(setP);
2277
+ else {
2278
+ // 如果没有指定timeout,设置一个永久标记,避免hget时误删
2279
+ await this.set(`${name}:${key}_ex`, 1);
2280
+ }
2281
+ return result;
1676
2282
  }
1677
2283
  /**
1678
2284
  * 哈希获取
@@ -1705,7 +2311,7 @@ class CacheStore {
1705
2311
  this.hdel(name, key);
1706
2312
  return 0;
1707
2313
  }
1708
- return dataArr[1] || 0;
2314
+ return Number(dataArr[1]) || 0;
1709
2315
  });
1710
2316
  }
1711
2317
  /**
@@ -1714,10 +2320,10 @@ class CacheStore {
1714
2320
  * @param key
1715
2321
  * @returns {*}
1716
2322
  */
1717
- hdel(name, key) {
1718
- const setP = [this.del(`${name}:${key}_ex`)];
1719
- setP.push(this.wrap('hdel', [`${this.options.keyPrefix || ""}${name}`, key]));
1720
- return Promise.all(setP);
2323
+ async hdel(name, key) {
2324
+ await this.del(`${name}:${key}_ex`);
2325
+ const result = await this.wrap('hdel', [`${this.options.keyPrefix || ""}${name}`, key]);
2326
+ return result;
1721
2327
  }
1722
2328
  /**
1723
2329
  * 返回哈希表 key 中域的数量
@@ -1731,11 +2337,11 @@ class CacheStore {
1731
2337
  * 给哈希表指定key,增加increment
1732
2338
  * @param name
1733
2339
  * @param key
1734
- * @param incr
2340
+ * @param increment
1735
2341
  * @returns {*}
1736
2342
  */
1737
- hincrby(name, key, incr = 1) {
1738
- return this.wrap('hincrby', [`${this.options.keyPrefix || ""}${name}`, key, incr]);
2343
+ hincrby(name, key, increment) {
2344
+ return this.wrap('hincrby', [`${this.options.keyPrefix || ""}${name}`, key, increment]);
1739
2345
  }
1740
2346
  /**
1741
2347
  * 返回哈希表所有key-value
@@ -1824,12 +2430,12 @@ class CacheStore {
1824
2430
  * @param timeout
1825
2431
  * @returns {*}
1826
2432
  */
1827
- sadd(name, value, timeout) {
1828
- const setP = [this.wrap('sadd', [`${this.options.keyPrefix || ""}${name}`, value])];
1829
- if (typeof timeout !== 'number') {
1830
- setP.push(this.wrap('expire', [`${this.options.keyPrefix || ""}${name}`, timeout]));
2433
+ async sadd(name, value, timeout) {
2434
+ const result = await this.wrap('sadd', [`${this.options.keyPrefix || ""}${name}`, value]);
2435
+ if (typeof timeout === 'number') {
2436
+ await this.wrap('expire', [`${this.options.keyPrefix || ""}${name}`, timeout]);
1831
2437
  }
1832
- return Promise.all(setP);
2438
+ return result;
1833
2439
  }
1834
2440
  /**
1835
2441
  * 返回集合的基数(集合中元素的数量)
@@ -1881,7 +2487,7 @@ class CacheStore {
1881
2487
  * @returns {*}
1882
2488
  */
1883
2489
  smove(source, destination, member) {
1884
- return this.wrap('smove', [`${this.options.keyPrefix || ""}${source}`, `${this.options.keyPrefix}${destination}`, member]);
2490
+ return this.wrap('smove', [`${this.options.keyPrefix || ""}${source}`, `${this.options.keyPrefix || ""}${destination}`, member]);
1885
2491
  }
1886
2492
  }
1887
2493