@abtnode/models 1.16.44 → 1.16.45-beta-20250609-082716-b6b0592b

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.
@@ -109,3 +109,4 @@ export declare function getConnectModels(): {
109
109
  export declare function setupModels(models: any, sequelize: Sequelize): void;
110
110
  type TableName = LiteralUnion<'users', string>;
111
111
  export declare function existsColumn(context: QueryInterface, tableName: TableName, columnName: string): Promise<boolean>;
112
+ export declare function cleanupSqliteMemory(sequelize: Sequelize, dbPath: string): Promise<void>;
@@ -23,6 +23,7 @@ exports.getServerModels = getServerModels;
23
23
  exports.getConnectModels = getConnectModels;
24
24
  exports.setupModels = setupModels;
25
25
  exports.existsColumn = existsColumn;
26
+ exports.cleanupSqliteMemory = cleanupSqliteMemory;
26
27
  const sequelize_1 = require("sequelize");
27
28
  const message_1 = require("./message");
28
29
  const account_1 = require("./account");
@@ -120,7 +121,12 @@ function createSequelize(dbPath, config = {
120
121
  sequelize = new sequelize_1.Sequelize('sqlite::memory:', config);
121
122
  }
122
123
  else {
123
- sequelize = new sequelize_1.Sequelize({ dialect: 'sqlite', storage: dbPath, ...config });
124
+ sequelize = new sequelize_1.Sequelize({
125
+ dialect: 'sqlite',
126
+ storage: dbPath,
127
+ pool: { max: 1, min: 0, idle: 10000, evict: 10000 },
128
+ ...config,
129
+ });
124
130
  const pragmas = async () => {
125
131
  await sequelize.query('pragma journal_mode = WAL;');
126
132
  await sequelize.query('pragma synchronous = normal;');
@@ -245,3 +251,30 @@ async function existsColumn(context, tableName, columnName) {
245
251
  const columnsDescription = await context.describeTable(tableName);
246
252
  return columnName in columnsDescription;
247
253
  }
254
+ // 定期清理 SQLite 内存
255
+ async function cleanupSqliteMemory(sequelize, dbPath) {
256
+ try {
257
+ // 检查连接状态
258
+ const [results] = await sequelize.query('SELECT 1');
259
+ if (!results || results.length === 0) {
260
+ return;
261
+ }
262
+ // 重置内存使用统计
263
+ await sequelize.query('PRAGMA shrink_memory;');
264
+ }
265
+ catch (err) {
266
+ // 如果是连接错误,说明连接已经断开
267
+ if (err.name === 'SequelizeConnectionError') {
268
+ console.warn('SQLite connection is closed, skip cleanup', { dbPath });
269
+ return;
270
+ }
271
+ console.error('Failed to cleanup SQLite memory:', err);
272
+ }
273
+ }
274
+ // 启动全局清理定时器
275
+ setInterval(async () => {
276
+ const cleanupPromises = Array.from(instances.entries())
277
+ .filter(([dbPath]) => !dbPath.endsWith(':memory:'))
278
+ .map(([dbPath, sequelize]) => cleanupSqliteMemory(sequelize, dbPath));
279
+ await Promise.all(cleanupPromises);
280
+ }, 60 * 1000 * 4);
@@ -1,7 +1,7 @@
1
1
  import { EventEmitter } from 'events';
2
2
  import { ModelDefined, OrderItem } from 'sequelize';
3
3
  import { MakeNullishOptional } from 'sequelize/types/utils';
4
- import SingleFlightLRUCache from '@abtnode/util/lib/single-flight-lru-cache';
4
+ import { DBCache } from '@abtnode/db-cache';
5
5
  import { AnyObject, SelectOptions, SortOptions, UpdateOptions, ConditionOptions, PagingOptions } from '../types';
6
6
  export declare class BaseState<T extends object> extends EventEmitter {
7
7
  model: ModelDefined<T, T>;
@@ -9,10 +9,11 @@ export declare class BaseState<T extends object> extends EventEmitter {
9
9
  config: AnyObject;
10
10
  ready: boolean;
11
11
  readyCallbacks: Function[];
12
- countCaches: SingleFlightLRUCache;
13
- enableCountCache: boolean;
12
+ countCaches: DBCache;
13
+ enableCountCache: string;
14
+ cacheGroup: string;
14
15
  constructor(model: ModelDefined<T, T>, config?: AnyObject);
15
- clearCountCache: () => void;
16
+ clearCountCache: () => Promise<void>;
16
17
  find(condition?: ConditionOptions<T>, selection?: SelectOptions<T>, sort?: SortOptions<T>): Promise<T[]>;
17
18
  findOne(condition?: ConditionOptions<T>, selection?: SelectOptions<T>, sort?: SortOptions<T>): Promise<T>;
18
19
  count(condition?: ConditionOptions<T>): Promise<number>;
@@ -7,17 +7,21 @@ exports.BaseState = void 0;
7
7
  const events_1 = require("events");
8
8
  const sequelize_1 = require("sequelize");
9
9
  const lodash_clonedeep_1 = __importDefault(require("lodash.clonedeep"));
10
- const single_flight_lru_cache_1 = __importDefault(require("@abtnode/util/lib/single-flight-lru-cache"));
10
+ const db_cache_1 = require("@abtnode/db-cache");
11
11
  const util_1 = require("../util");
12
12
  // eslint-disable-next-line import/prefer-default-export
13
13
  class BaseState extends events_1.EventEmitter {
14
14
  constructor(model, config = {}) {
15
15
  super();
16
- this.clearCountCache = () => {
17
- this.countCaches.clear();
16
+ this.clearCountCache = async () => {
17
+ await this.countCaches.del(this.enableCountCache);
18
18
  };
19
- this.countCaches = new single_flight_lru_cache_1.default({ max: 10 * 1000, ttl: 1000 * 60 * 5 });
20
- this.enableCountCache = false;
19
+ this.countCaches = new db_cache_1.DBCache(() => ({
20
+ ...(0, db_cache_1.getAbtNodeRedisAndSQLiteUrl)(),
21
+ prefix: 'base-models',
22
+ ttl: 1000 * 60 * 2,
23
+ }));
24
+ this.enableCountCache = '';
21
25
  this.model = model;
22
26
  this.config = Object.freeze((0, lodash_clonedeep_1.default)(config));
23
27
  // Just used to minic ready callbacks of @abtnode/db
@@ -49,19 +53,22 @@ class BaseState extends events_1.EventEmitter {
49
53
  }
50
54
  count(condition = {}) {
51
55
  const params = { ...(0, util_1.formatConditions)(condition) };
56
+ if (!this.enableCountCache) {
57
+ return this.model.count(params);
58
+ }
52
59
  const key = this.enableCountCache ? JSON.stringify(params) : '';
53
- return this.countCaches.autoCache(key, () => {
60
+ return this.countCaches.autoCacheGroup(this.enableCountCache, key, () => {
54
61
  return this.model.count(params);
55
62
  });
56
63
  }
57
64
  async insert(doc) {
58
- this.clearCountCache();
65
+ await this.clearCountCache();
59
66
  const newDoc = await this.model.create(doc, { returning: true });
60
67
  await newDoc.save();
61
68
  return newDoc.toJSON();
62
69
  }
63
70
  async insertMany(docs) {
64
- this.clearCountCache();
71
+ await this.clearCountCache();
65
72
  const newDocs = await this.model.bulkCreate(docs, { returning: true });
66
73
  return newDocs.map((x) => x.toJSON());
67
74
  }
@@ -69,7 +76,7 @@ class BaseState extends events_1.EventEmitter {
69
76
  if (arguments.length < 2) {
70
77
  throw new Error('condition and update param are required to update database record');
71
78
  }
72
- this.clearCountCache();
79
+ await this.clearCountCache();
73
80
  if (typeof condition === 'string') {
74
81
  return this.updateById(condition, updates, options);
75
82
  }
@@ -89,7 +96,7 @@ class BaseState extends events_1.EventEmitter {
89
96
  return this.update({ id }, updates, options);
90
97
  }
91
98
  async upsert(condition, updates) {
92
- this.clearCountCache();
99
+ await this.clearCountCache();
93
100
  const [instance] = await this.model.upsert(Object.assign({}, condition, updates.$set || updates));
94
101
  return instance.toJSON();
95
102
  }
@@ -124,8 +131,8 @@ class BaseState extends events_1.EventEmitter {
124
131
  },
125
132
  };
126
133
  }
127
- remove(condition) {
128
- this.clearCountCache();
134
+ async remove(condition) {
135
+ await this.clearCountCache();
129
136
  return this.model.destroy((0, util_1.formatConditions)(condition));
130
137
  }
131
138
  max(field, condition = {}) {
@@ -140,8 +147,8 @@ class BaseState extends events_1.EventEmitter {
140
147
  query(query) {
141
148
  return this.model.sequelize.query(query, { type: sequelize_1.QueryTypes.SELECT });
142
149
  }
143
- reset() {
144
- this.clearCountCache();
150
+ async reset() {
151
+ await this.clearCountCache();
145
152
  return this.model.destroy({ truncate: true });
146
153
  }
147
154
  build(row) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abtnode/models",
3
- "version": "1.16.44",
3
+ "version": "1.16.45-beta-20250609-082716-b6b0592b",
4
4
  "description": "Sequelize models for blocklet server and blocklet service",
5
5
  "homepage": "https://github.com/ArcBlock/blocklet-server#readme",
6
6
  "publishConfig": {
@@ -33,10 +33,11 @@
33
33
  "url": "https://github.com/ArcBlock/blocklet-server/issues"
34
34
  },
35
35
  "dependencies": {
36
- "@abtnode/constant": "1.16.44",
37
- "@abtnode/logger": "1.16.44",
38
- "@abtnode/types": "1.16.44",
39
- "@abtnode/util": "1.16.44",
36
+ "@abtnode/constant": "1.16.45-beta-20250609-082716-b6b0592b",
37
+ "@abtnode/db-cache": "1.16.45-beta-20250609-082716-b6b0592b",
38
+ "@abtnode/logger": "1.16.45-beta-20250609-082716-b6b0592b",
39
+ "@abtnode/types": "1.16.45-beta-20250609-082716-b6b0592b",
40
+ "@abtnode/util": "1.16.45-beta-20250609-082716-b6b0592b",
40
41
  "lodash.clonedeep": "^4.5.0",
41
42
  "lodash.isempty": "^4.4.0",
42
43
  "sequelize": "^6.35.0",
@@ -56,5 +57,5 @@
56
57
  "typescript": "^5.6.3"
57
58
  },
58
59
  "resolutions": {},
59
- "gitHead": "a177f040e3e8da94311cec1395c8e8defae2da9e"
60
+ "gitHead": "adeceb28a9b5c91d2eb35d33880782048ae629cc"
60
61
  }