midway-fatcms 0.0.16 → 0.0.17

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.
Files changed (119) hide show
  1. package/dist/config/config.default.js +5 -3
  2. package/dist/configuration.d.ts +0 -3
  3. package/dist/configuration.js +0 -19
  4. package/dist/controller/gateway/ProxyApiGatewayController.d.ts +0 -2
  5. package/dist/controller/gateway/ProxyApiGatewayController.js +0 -18
  6. package/dist/controller/helpers.controller.d.ts +4 -5
  7. package/dist/controller/helpers.controller.js +56 -14
  8. package/dist/controller/manage/AccountRoleManageApi.js +3 -5
  9. package/dist/controller/manage/AnyApiMangeApi.js +4 -3
  10. package/dist/controller/manage/AppMangeApi.js +3 -4
  11. package/dist/controller/manage/AppPageMangeApi.js +4 -3
  12. package/dist/controller/manage/CrudMethodsMangeApi.js +3 -4
  13. package/dist/controller/manage/DataDictManageApi.js +6 -7
  14. package/dist/controller/manage/DeployManageApi.js +4 -5
  15. package/dist/controller/manage/FlowConfigManageApi.js +3 -5
  16. package/dist/controller/manage/MenuManageApi.js +3 -4
  17. package/dist/controller/manage/ProxyApiMangeApi.js +3 -4
  18. package/dist/controller/manage/SysConfigMangeApi.js +3 -3
  19. package/dist/controller/manage/SystemInfoManageApi.js +3 -1
  20. package/dist/controller/manage/WorkbenchMangeApi.js +3 -4
  21. package/dist/index.d.ts +3 -0
  22. package/dist/index.js +3 -0
  23. package/dist/libs/crud-pro/models/TransactionSqlServer.js +27 -4
  24. package/dist/libs/crud-pro/services/CrudProCachedCfgService.d.ts +5 -8
  25. package/dist/libs/crud-pro/services/CrudProCachedCfgService.js +25 -42
  26. package/dist/libs/crud-pro/utils/CrudMonitor.d.ts +0 -9
  27. package/dist/libs/crud-pro/utils/CrudMonitor.js +0 -21
  28. package/dist/libs/crud-pro/utils/pool/SqlServerUtils.js +26 -0
  29. package/dist/middleware/cacherefresh.middleware.d.ts +3 -46
  30. package/dist/middleware/cacherefresh.middleware.js +9 -67
  31. package/dist/models/CacheRefreshCategory.d.ts +1 -18
  32. package/dist/models/CacheRefreshCategory.js +0 -17
  33. package/dist/models/SystemEntities.d.ts +2 -0
  34. package/dist/models/bizmodels.d.ts +0 -8
  35. package/dist/models/bizmodels.js +0 -8
  36. package/dist/schedule/scheduleNames.d.ts +2 -0
  37. package/dist/schedule/scheduleNames.js +3 -1
  38. package/dist/service/SysAppService.d.ts +2 -5
  39. package/dist/service/SysAppService.js +15 -69
  40. package/dist/service/SysConfigService.d.ts +1 -6
  41. package/dist/service/SysConfigService.js +7 -46
  42. package/dist/service/SysDictDataService.d.ts +2 -5
  43. package/dist/service/SysDictDataService.js +13 -59
  44. package/dist/service/SysMenuService.d.ts +1 -4
  45. package/dist/service/SysMenuService.js +6 -42
  46. package/dist/service/WorkbenchService.d.ts +1 -5
  47. package/dist/service/WorkbenchService.js +10 -61
  48. package/dist/service/anyapi/AnyApiService.d.ts +1 -1
  49. package/dist/service/anyapi/AnyApiService.js +6 -16
  50. package/dist/service/base/bizmemcache/BizMemCacheService.d.ts +16 -0
  51. package/dist/service/base/bizmemcache/BizMemCacheService.js +239 -0
  52. package/dist/service/base/bizmemcache/BizMemCacheStore.d.ts +34 -0
  53. package/dist/service/base/bizmemcache/BizMemCacheStore.js +118 -0
  54. package/dist/service/base/bizmemcache/BizMemCacheTypes.d.ts +60 -0
  55. package/dist/service/base/bizmemcache/BizMemCacheTypes.js +18 -0
  56. package/dist/service/base/cache-refresh/CacheRefreshHub.d.ts +0 -22
  57. package/dist/service/base/cache-refresh/CacheRefreshHub.js +0 -22
  58. package/dist/service/base/cache-refresh/CacheRefreshHubScheduleService.d.ts +0 -6
  59. package/dist/service/base/cache-refresh/CacheRefreshHubScheduleService.js +0 -6
  60. package/dist/service/curd/CurdMixByDictService.d.ts +0 -4
  61. package/dist/service/curd/CurdMixByDictService.js +9 -55
  62. package/dist/service/curd/CurdMixBySysConfigService.d.ts +0 -5
  63. package/dist/service/curd/CurdMixBySysConfigService.js +9 -54
  64. package/dist/service/curd/CurdMixByWorkbenchService.d.ts +0 -1
  65. package/dist/service/curd/CurdMixByWorkbenchService.js +9 -36
  66. package/dist/service/curd/CurdProService.d.ts +0 -1
  67. package/dist/service/curd/CurdProService.js +0 -4
  68. package/dist/service/proxyapi/ProxyApiLoadService.d.ts +3 -8
  69. package/dist/service/proxyapi/ProxyApiLoadService.js +40 -68
  70. package/dist/service/proxyapi/ProxyApiService.d.ts +2 -0
  71. package/dist/service/proxyapi/ProxyApiService.js +32 -9
  72. package/dist/service/proxyapi/RouteTrie.d.ts +1 -7
  73. package/dist/service/proxyapi/RouteTrie.js +1 -17
  74. package/package.json +1 -1
  75. package/src/config/config.default.ts +4 -2
  76. package/src/configuration.ts +0 -23
  77. package/src/controller/gateway/ProxyApiGatewayController.ts +1 -9
  78. package/src/controller/helpers.controller.ts +66 -15
  79. package/src/controller/manage/AccountRoleManageApi.ts +3 -5
  80. package/src/controller/manage/AnyApiMangeApi.ts +4 -3
  81. package/src/controller/manage/AppMangeApi.ts +4 -5
  82. package/src/controller/manage/AppPageMangeApi.ts +4 -3
  83. package/src/controller/manage/CrudMethodsMangeApi.ts +4 -5
  84. package/src/controller/manage/DataDictManageApi.ts +7 -8
  85. package/src/controller/manage/DeployManageApi.ts +2 -3
  86. package/src/controller/manage/FlowConfigManageApi.ts +3 -5
  87. package/src/controller/manage/MenuManageApi.ts +4 -5
  88. package/src/controller/manage/ProxyApiMangeApi.ts +4 -5
  89. package/src/controller/manage/SysConfigMangeApi.ts +5 -5
  90. package/src/controller/manage/SystemInfoManageApi.ts +3 -1
  91. package/src/controller/manage/WorkbenchMangeApi.ts +4 -5
  92. package/src/index.ts +3 -0
  93. package/src/libs/crud-pro/models/TransactionSqlServer.ts +26 -4
  94. package/src/libs/crud-pro/services/CrudProCachedCfgService.ts +25 -43
  95. package/src/libs/crud-pro/utils/CrudMonitor.ts +0 -23
  96. package/src/libs/crud-pro/utils/pool/SqlServerUtils.ts +31 -0
  97. package/src/middleware/cacherefresh.middleware.ts +10 -71
  98. package/src/models/CacheRefreshCategory.ts +0 -17
  99. package/src/models/SystemEntities.ts +2 -0
  100. package/src/models/bizmodels.ts +0 -8
  101. package/src/schedule/scheduleNames.ts +5 -3
  102. package/src/service/SysAppService.ts +13 -66
  103. package/src/service/SysConfigService.ts +6 -39
  104. package/src/service/SysDictDataService.ts +11 -56
  105. package/src/service/SysMenuService.ts +4 -37
  106. package/src/service/WorkbenchService.ts +10 -68
  107. package/src/service/anyapi/AnyApiService.ts +5 -17
  108. package/src/service/base/bizmemcache/BizMemCacheService.ts +288 -0
  109. package/src/service/base/bizmemcache/BizMemCacheStore.ts +158 -0
  110. package/src/service/base/bizmemcache/BizMemCacheTypes.ts +76 -0
  111. package/src/service/base/cache-refresh/CacheRefreshHub.ts +0 -22
  112. package/src/service/base/cache-refresh/CacheRefreshHubScheduleService.ts +0 -6
  113. package/src/service/curd/CurdMixByDictService.ts +10 -61
  114. package/src/service/curd/CurdMixBySysConfigService.ts +9 -62
  115. package/src/service/curd/CurdMixByWorkbenchService.ts +7 -32
  116. package/src/service/curd/CurdProService.ts +0 -6
  117. package/src/service/proxyapi/ProxyApiLoadService.ts +39 -77
  118. package/src/service/proxyapi/ProxyApiService.ts +45 -9
  119. package/src/service/proxyapi/RouteTrie.ts +1 -18
@@ -3,8 +3,8 @@ import { Context } from '@midwayjs/koa';
3
3
  import { KeysOfSimpleSQL, KeysOfValidators } from '@/libs/crud-pro/models/keys';
4
4
  import { BaseApiController } from '../base/BaseApiController';
5
5
  import { checkPermission } from '@/middleware/permission.middleware';
6
- import { refreshCache } from '@/middleware/cacherefresh.middleware';
7
- import { CacheNameEnum, CTX_WORKBENCH_CODE } from '@/models/bizmodels';
6
+ import { refreshBizMemCache } from '@/middleware/cacherefresh.middleware';
7
+ import { CTX_WORKBENCH_CODE } from '@/models/bizmodels';
8
8
  import { SystemFuncCode } from '@/models/SystemPerm';
9
9
  import { SystemTables } from '@/models/SystemTables';
10
10
  import { CommonResult } from '@/libs/utils/common-dto';
@@ -35,7 +35,7 @@ export class SysConfigMangeApi extends BaseApiController {
35
35
  });
36
36
  }
37
37
 
38
- @Post('/createSysConfig', { middleware: [checkPermission(SystemFuncCode.SysConfigMangeWrite), refreshCache(CacheNameEnum.GetSysConfigOne)] })
38
+ @Post('/createSysConfig', { middleware: [checkPermission(SystemFuncCode.SysConfigMangeWrite), refreshBizMemCache('sysConfgCacheObj')] })
39
39
  async createSysConfig() {
40
40
  return this.executeSysSimpleSQL('sys_configs', KeysOfSimpleSQL.SIMPLE_INSERT, {
41
41
  enableSoftDelete: true,
@@ -51,7 +51,7 @@ export class SysConfigMangeApi extends BaseApiController {
51
51
  });
52
52
  }
53
53
 
54
- @Post('/updateSysConfig', { middleware: [checkPermission(SystemFuncCode.SysConfigMangeWrite), refreshCache(CacheNameEnum.GetSysConfigOne)] })
54
+ @Post('/updateSysConfig', { middleware: [checkPermission(SystemFuncCode.SysConfigMangeWrite), refreshBizMemCache('sysConfgCacheObj')] })
55
55
  async updateSysConfig() {
56
56
  const { SystemDbName, SystemDbType } = GLOBAL_STATIC_CONFIG.getConfig();
57
57
 
@@ -94,7 +94,7 @@ export class SysConfigMangeApi extends BaseApiController {
94
94
  return result;
95
95
  }
96
96
 
97
- @Post('/deleteSysConfig', { middleware: [checkPermission(SystemFuncCode.SysConfigMangeWrite), refreshCache(CacheNameEnum.GetSysConfigOne)] })
97
+ @Post('/deleteSysConfig', { middleware: [checkPermission(SystemFuncCode.SysConfigMangeWrite), refreshBizMemCache('sysConfgCacheObj')] })
98
98
  async deleteSysConfig() {
99
99
  return this.executeSysSimpleSQL('sys_configs', KeysOfSimpleSQL.SIMPLE_DELETE, {
100
100
  enableSoftDelete: true,
@@ -5,6 +5,7 @@ import { BaseApiController } from '../base/BaseApiController';
5
5
  import { SystemFuncCode } from '@/models/SystemPerm';
6
6
  import { CommonResult } from '@/libs/utils/common-dto';
7
7
  import { CrudMonitor } from "@/libs/crud-pro/utils/CrudMonitor";
8
+ import { bizMemCacheStore } from '@/service/base/bizmemcache/BizMemCacheStore';
8
9
 
9
10
  @Controller('/ns/api/manage/systemInfo',)
10
11
  export class SystemInfoManageApi extends BaseApiController {
@@ -59,7 +60,8 @@ export class SystemInfoManageApi extends BaseApiController {
59
60
  timeInfo,
60
61
  envInfo,
61
62
  networkInfo,
62
- crudMonitorInfo: CrudMonitor
63
+ crudMonitorInfo: CrudMonitor,
64
+ bizMemCacheLastTime: bizMemCacheStore.getLastTimeSnapshot(),
63
65
  });
64
66
  }
65
67
  }
@@ -3,8 +3,7 @@ import { Context } from '@midwayjs/koa';
3
3
  import { KeysOfSimpleSQL, KeysOfValidators } from '@/libs/crud-pro/models/keys';
4
4
  import { BaseApiController } from '../base/BaseApiController';
5
5
  import { checkPermission } from '@/middleware/permission.middleware';
6
- import { refreshCache } from '@/middleware/cacherefresh.middleware';
7
- import { CacheNameEnum } from '@/models/bizmodels';
6
+ import { refreshBizMemCache } from '@/middleware/cacherefresh.middleware';
8
7
  import { SystemFuncCode } from '@/models/SystemPerm';
9
8
  import { SystemTables } from '@/models/SystemTables';
10
9
 
@@ -27,7 +26,7 @@ export class WorkbenchMangeApi extends BaseApiController {
27
26
  });
28
27
  }
29
28
 
30
- @Post('/createWorkbench', { middleware: [checkPermission(SystemFuncCode.WorkbenchMangeWrite), refreshCache([CacheNameEnum.GetWorkbenchCachedObj, CacheNameEnum.CurdMixByWorkbench])] })
29
+ @Post('/createWorkbench', { middleware: [checkPermission(SystemFuncCode.WorkbenchMangeWrite), refreshBizMemCache('workbenchCachedObj')] })
31
30
  async createWorkbench() {
32
31
 
33
32
  const body = this.ctx.request.body as any;
@@ -45,7 +44,7 @@ export class WorkbenchMangeApi extends BaseApiController {
45
44
  });
46
45
  }
47
46
 
48
- @Post('/updateWorkbench', { middleware: [checkPermission(SystemFuncCode.WorkbenchMangeWrite), refreshCache([CacheNameEnum.GetWorkbenchCachedObj, CacheNameEnum.CurdMixByWorkbench])] })
47
+ @Post('/updateWorkbench', { middleware: [checkPermission(SystemFuncCode.WorkbenchMangeWrite), refreshBizMemCache('workbenchCachedObj')] })
49
48
  async updateWorkbench() {
50
49
 
51
50
  return this.executeSysSimpleSQL(SystemTables.sys_workbench, KeysOfSimpleSQL.SIMPLE_UPDATE, {
@@ -57,7 +56,7 @@ export class WorkbenchMangeApi extends BaseApiController {
57
56
  });
58
57
  }
59
58
 
60
- @Post('/deleteWorkbench', { middleware: [checkPermission(SystemFuncCode.WorkbenchMangeWrite), refreshCache([CacheNameEnum.GetWorkbenchCachedObj, CacheNameEnum.CurdMixByWorkbench])] })
59
+ @Post('/deleteWorkbench', { middleware: [checkPermission(SystemFuncCode.WorkbenchMangeWrite), refreshBizMemCache('workbenchCachedObj')] })
61
60
  async deleteWorkbench() {
62
61
 
63
62
  return this.executeSysSimpleSQL(SystemTables.sys_workbench, KeysOfSimpleSQL.SIMPLE_DELETE, {
package/src/index.ts CHANGED
@@ -59,6 +59,9 @@ export * from './service/UserAccountService';
59
59
  export * from './service/UserSessionService';
60
60
  export * from './service/VisitStatService';
61
61
  export * from './service/WorkbenchService';
62
+ export * from './service/base/bizmemcache/BizMemCacheService';
63
+ export * from './service/base/bizmemcache/BizMemCacheTypes';
64
+ export * from './service/base/bizmemcache/BizMemCacheStore';
62
65
  export * from './service/anyapi/AnyApiSandboxService';
63
66
  export * from './service/anyapi/AnyApiService';
64
67
  export * from './service/base/ApiBaseService';
@@ -8,11 +8,16 @@ import * as _ from 'lodash';
8
8
  class SqlServerConnectionClient implements IPoolConnectionClient {
9
9
  originConnection: ConnectionPool;
10
10
  private sqlServerTransaction: Transaction;
11
+ private isReleased: boolean = false;
11
12
  constructor(originConnection: ConnectionPool) {
12
13
  this.originConnection = originConnection;
14
+ CrudMonitor.mssqlGetConnectionCount++;
13
15
  }
14
16
  async query(sql: string, values: any[]): Promise<IPoolConnectionQueryResult> {
15
- const request = new Request(this.originConnection);
17
+ // 如果存在活跃的事务,请求应该绑定到事务上,否则事务不生效
18
+ const request = this.sqlServerTransaction
19
+ ? new Request(this.sqlServerTransaction)
20
+ : new Request(this.originConnection);
16
21
 
17
22
  if (Array.isArray(values)) {
18
23
  for (let i = 0; i < values.length; i++) {
@@ -41,18 +46,35 @@ class SqlServerConnectionClient implements IPoolConnectionClient {
41
46
 
42
47
  async commit() {
43
48
  const tmpTx = this.sqlServerTransaction;
44
- await tmpTx.commit();
49
+ if (tmpTx) {
50
+ await tmpTx.commit();
51
+ }
45
52
  }
46
53
 
47
54
  async rollback() {
48
55
  const tmpTx = this.sqlServerTransaction;
49
- await tmpTx.rollback();
56
+ if (tmpTx) {
57
+ await tmpTx.rollback();
58
+ }
50
59
  }
51
60
 
52
61
 
53
62
  async release() {
63
+ if (this.isReleased) {
64
+ return;
65
+ }
66
+ this.isReleased = true;
54
67
  try {
55
- CrudMonitor.postgresReleaseConnectionCount++;
68
+ // 如果有未结束的事务,先回滚
69
+ if (this.sqlServerTransaction) {
70
+ try {
71
+ await this.sqlServerTransaction.rollback();
72
+ } catch (e) {
73
+ // 事务可能已经回滚或提交,忽略错误
74
+ }
75
+ this.sqlServerTransaction = null;
76
+ }
77
+ CrudMonitor.mssqlReleaseConnectionCount++;
56
78
  } catch (e) {
57
79
  console.log('[crud-pro] SqlServerConnectionClient release ', e);
58
80
  }
@@ -3,19 +3,28 @@ import { CrudProServiceBase } from './CrudProServiceBase';
3
3
  import { IRequestCfgModel } from '../interfaces';
4
4
  import { MixinUtils } from '../utils/MixinUtils';
5
5
  import { ICurdProServiceHub } from '../models/ServiceHub';
6
- // import { pickAndConvertRowsByMix } from '../utils/sqlConvert/convertMix';
7
- import MemoryRefreshCache from '../utils/MemoryRefreshCache';
8
- const DEFAULT_KEEP_TIME = 1000 * 60 * 60 * 24 * 365; // 内存缓存时间默认 1年
9
6
 
10
- const methodCache = new MemoryRefreshCache();
7
+ /** 由上层 BizMemCache 注入的方法配置缓存,key 为 method */
8
+ let externalMethodCacheMap: Record<string, IRequestCfgModel> | null = null;
11
9
 
12
- function parseMethodInfo(row: any): any {
13
- const methodInfo: any = camelizeKeys(row); //转换成驼峰
10
+ export function parseCrudMethodInfo(row: any): IRequestCfgModel {
11
+ const methodInfo: any = camelizeKeys(row);
14
12
  const configObject = MixinUtils.parseJsonObject(methodInfo.moreConfig) || {};
15
13
  const sqlCfgList = MixinUtils.parseJsonObject(methodInfo.sqlCfgList) || [];
16
14
  return { ...configObject, ...methodInfo, sqlCfgList };
17
15
  }
18
16
 
17
+ /**
18
+ * 注入 CRUD 方法配置缓存(由 BizMemCache 加载后调用)
19
+ */
20
+ export function setMethodCache(methodInfoList: IRequestCfgModel[] | null): void {
21
+ if (!methodInfoList) {
22
+ externalMethodCacheMap = null;
23
+ return;
24
+ }
25
+ externalMethodCacheMap = MixinUtils.toMap(methodInfoList, item => item.method);
26
+ }
27
+
19
28
  class CrudProCachedCfgService extends CrudProServiceBase {
20
29
  constructor(serviceHub: ICurdProServiceHub) {
21
30
  super(serviceHub);
@@ -30,26 +39,24 @@ class CrudProCachedCfgService extends CrudProServiceBase {
30
39
  }
31
40
 
32
41
  private async getCachedCfgByMethodInner(method: string, isEnableCache: boolean): Promise<IRequestCfgModel | null> {
33
- // 不使用缓存
34
42
  if (!isEnableCache) {
35
43
  return await this.loadMethodInfo(method);
36
44
  }
37
45
 
38
- methodCache.setProps({
39
- keepTime: DEFAULT_KEEP_TIME, // 1年
40
- requestFn: () => this.loadMethodInfoList(),
41
- getKeyFn: item => item.method,
42
- });
43
- const methodInfo = await methodCache.getItem(method);
44
- if (methodInfo) {
45
- return methodInfo;
46
+ if (externalMethodCacheMap) {
47
+ const methodInfo = externalMethodCacheMap[method];
48
+ if (methodInfo) {
49
+ return methodInfo;
50
+ }
46
51
  }
52
+
53
+ // 缓存未就绪或未命中时,降级单条查询
47
54
  return await this.loadMethodInfo(method);
48
55
  }
49
56
 
50
- private async loadMethodInfo(method: string): Promise<any> {
57
+ private async loadMethodInfo(method: string): Promise<IRequestCfgModel | null> {
51
58
  const { methodsTableName, sysDatabaseName, sysDatabaseDbType } = this.getContextCfg();
52
- const sql = `select * from ${methodsTableName} where method = ? `; // 全部加载到内存
59
+ const sql = `select * from ${methodsTableName} where method = ? `;
53
60
 
54
61
  const baseInfo = {
55
62
  sqlTable: methodsTableName,
@@ -60,35 +67,10 @@ class CrudProCachedCfgService extends CrudProServiceBase {
60
67
  const queryRes = await this.executeUnsafeQuery(baseInfo, sql, [method]);
61
68
  const rows2: any[] = queryRes.rows || [];
62
69
  if (rows2.length > 0) {
63
- return parseMethodInfo(rows2[0]);
70
+ return parseCrudMethodInfo(rows2[0]);
64
71
  }
65
72
  return null;
66
73
  }
67
-
68
- private async loadMethodInfoList(): Promise<any[]> {
69
- const { methodsTableName, sysDatabaseName, sysDatabaseDbType } = this.getContextCfg();
70
- const sql = `select * from ${methodsTableName}`; // 全部加载到内存
71
- const baseInfo = {
72
- sqlTable: methodsTableName,
73
- sqlDatabase: sysDatabaseName,
74
- sqlDbType: sysDatabaseDbType,
75
- };
76
- const queryRes = await this.executeUnsafeQuery(baseInfo, sql);
77
- const rows2: any[] = queryRes.rows || [];
78
- return rows2.map(row => {
79
- return parseMethodInfo(row);
80
- });
81
- }
82
74
  }
83
75
 
84
76
  export { CrudProCachedCfgService };
85
-
86
- /**
87
- * 清空 CRUD 方法配置缓存(独立函数,无需实例化 Service 即可调用)
88
- *
89
- * 清空后,下次请求会自动从数据库重新加载(懒加载刷新)。
90
- * 适用于 manage 增删改触发刷新、定时刷新等场景。
91
- */
92
- export function clearMethodCache(): void {
93
- methodCache.clear();
94
- }
@@ -3,10 +3,8 @@ import { CacheNameEnum } from '@/models/bizmodels';
3
3
  import { CacheRefreshCategory } from '@/models/CacheRefreshCategory';
4
4
 
5
5
  export type CacheLastRefreshTimeMap = {
6
- // CacheRefreshCategory 缓存类别
7
6
  [K in CacheRefreshCategory]: number | null;
8
7
  } & {
9
- // CacheNameEnum 业务缓存
10
8
  [K in CacheNameEnum]: number | null;
11
9
  };
12
10
 
@@ -20,42 +18,21 @@ const CrudMonitor = {
20
18
  mssqlGetConnectionCount: 0,
21
19
  mssqlReleaseConnectionCount: 0,
22
20
 
23
- /** 每个缓存项的最近一次刷新时间(时间戳 ms),null 表示尚未刷新 */
24
21
  cacheLastRefreshTime: {
25
- // CacheRefreshCategory
26
22
  [CacheRefreshCategory.TableMeta]: null,
27
23
  [CacheRefreshCategory.CacheService]: null,
28
24
  [CacheRefreshCategory.LinkToCustom]: null,
29
- [CacheRefreshCategory.ProxyApiRoute]: null,
30
- [CacheRefreshCategory.CrudMethodConfig]: null,
31
- // CacheNameEnum
32
25
  [CacheNameEnum.CurdMixByAccount]: null,
33
- [CacheNameEnum.CurdMixByDict]: null,
34
26
  [CacheNameEnum.CurdMixByLinkToCustom]: null,
35
- [CacheNameEnum.CurdMixByWorkbench]: null,
36
- [CacheNameEnum.GetSysConfigOne]: null,
37
- [CacheNameEnum.GetDataDictItemsByDictCode]: null,
38
- [CacheNameEnum.GetWorkbenchCachedObj]: null,
39
- [CacheNameEnum.GetSysAppOne]: null,
40
- [CacheNameEnum.GetSysAppPageOne]: null,
41
- [CacheNameEnum.GetSysMenusList]: null,
42
27
  [CacheNameEnum.GetFlowConfigOne]: null,
43
28
  [CacheNameEnum.UserSessionBySessionId]: null,
44
29
  [CacheNameEnum.UserSessionByAsyncTaskId]: null,
45
30
  } as CacheLastRefreshTimeMap,
46
31
 
47
- /**
48
- * 记录缓存刷新时间
49
- * @param key 缓存类别或缓存名
50
- */
51
32
  markCacheRefreshed(key: CacheRefreshKey): void {
52
33
  (this.cacheLastRefreshTime as any)[key] = Date.now();
53
34
  },
54
35
 
55
- /**
56
- * 获取缓存最近刷新时间
57
- * @param key 缓存类别或缓存名
58
- */
59
36
  getCacheLastRefreshTime(key: CacheRefreshKey): number | null {
60
37
  return (this.cacheLastRefreshTime as any)[key] ?? null;
61
38
  },
@@ -3,12 +3,43 @@ import { IConnectionPool } from '../../interfaces';
3
3
  import { SqlDbType } from '../../models/keys';
4
4
 
5
5
  const POOL_CACHE_MAP: Record<string, IConnectionPool> = {};
6
+ const POOL_CONNECTING_MAP: Record<string, Promise<ConnectionPool>> = {};
7
+
8
+ async function doConnectPool(poolName: string, poolObj: ConnectionPool): Promise<ConnectionPool> {
9
+ // 避免重复连接同一个池
10
+ if (POOL_CONNECTING_MAP[poolName]) {
11
+ return POOL_CONNECTING_MAP[poolName];
12
+ }
13
+
14
+ const connectPromise = poolObj.connect().then((connectedPool) => {
15
+ console.log(`[crud-pro] SQL Server connection pool "${poolName}" connected successfully.`);
16
+ return connectedPool;
17
+ }).catch((err) => {
18
+ console.error(`[crud-pro] SQL Server connection pool "${poolName}" connect failed:`, err);
19
+ throw err;
20
+ }).finally(() => {
21
+ delete POOL_CONNECTING_MAP[poolName];
22
+ });
23
+
24
+ POOL_CONNECTING_MAP[poolName] = connectPromise;
25
+ return connectPromise;
26
+ }
6
27
 
7
28
  function getConnectionPool(poolName: string, poolOptions: any): IConnectionPool {
8
29
  let pool = POOL_CACHE_MAP[poolName];
9
30
  if (!pool) {
10
31
  const poolObj = new ConnectionPool(poolOptions);
11
32
 
33
+ // 监听连接池错误,避免未捕获的异常导致进程崩溃
34
+ poolObj.on('error', (err) => {
35
+ console.error(`[crud-pro] SQL Server connection pool "${poolName}" error:`, err);
36
+ });
37
+
38
+ // 预连接池,避免首次请求时才建立连接导致延迟
39
+ doConnectPool(poolName, poolObj).catch(() => {
40
+ // 错误已在 doConnectPool 中打印,此处无需重复处理
41
+ });
42
+
12
43
  pool = {
13
44
  dbType: SqlDbType.sqlserver,
14
45
  poolName: poolName,
@@ -1,80 +1,19 @@
1
- import { NextFunction, Context, IMidwayKoaContext } from '@midwayjs/koa';
2
- import { CacheNameEnum } from '@/models/bizmodels';
3
- import { CacheRefreshCategory } from '@/models/CacheRefreshCategory';
4
- import { CacheServiceFactory } from '@/service/base/cache/CacheServiceFactory';
5
- import { CacheRefreshHub } from '@/service/base/cache-refresh/CacheRefreshHub';
1
+ import { NextFunction, Context } from '@midwayjs/koa';
2
+ import { RedisService } from '@midwayjs/redis';
3
+ import { bizMemCacheStore } from '@/service/base/bizmemcache/BizMemCacheStore';
4
+ import { BizMemCacheKey } from '@/service/base/bizmemcache/BizMemCacheTypes';
6
5
 
7
- /**
8
- * 缓存刷新中间件
9
- *
10
- * 在路由处理成功完成后,自动触发指定缓存项的刷新。
11
- * 采用后置刷新模式:先 await next() 让业务逻辑执行完毕,再刷新缓存。
12
- *
13
- * 应用场景:
14
- * 1. manage 增删改操作后自动刷新关联的业务缓存
15
- * 2. 精准刷新:只刷新与本次操作相关的缓存项,避免全量刷新
16
- *
17
- * 使用示例:
18
- * ```typescript
19
- * // 刷新全部业务缓存(向后兼容,等同原来的 refreshCache())
20
- * @Post('/createRole', { middleware: [checkPermission('write'), refreshCache()] })
21
- * async createRole() { ... }
22
- *
23
- * // 精准刷新:只刷新指定缓存项
24
- * @Post('/createMenu', { middleware: [checkPermission('write'), refreshCache(CacheNameEnum.GetSysMenusList)] })
25
- * async createMenu() { ... }
26
- *
27
- * // 同时刷新多个缓存项
28
- * @Post('/createApp', { middleware: [checkPermission('write'), refreshCache([CacheNameEnum.GetSysAppOne, CacheNameEnum.GetSysAppPageOne])] })
29
- * async createApp() { ... }
30
- * ```
31
- *
32
- * @param cacheName 缓存名称,不传则刷新全部,支持单个或数组
33
- */
34
- function refreshCache(cacheName?: CacheNameEnum | CacheNameEnum[]) {
35
- const cacheNames = cacheName ? (Array.isArray(cacheName) ? cacheName : [cacheName]) : null;
6
+ function refreshBizMemCache(cacheKey: BizMemCacheKey | BizMemCacheKey[]) {
7
+ const cacheKeys = Array.isArray(cacheKey) ? cacheKey : [cacheKey];
36
8
 
37
9
  return async (ctx: Context, next: NextFunction) => {
38
10
  await next();
39
11
 
40
- const cacheServiceFactory = await ctx.requestContext.getAsync(CacheServiceFactory);
41
-
42
- if (cacheNames) {
43
- // 精准刷新:只刷新指定的缓存项
44
- for (const name of cacheNames) {
45
- await cacheServiceFactory.refreshByCacheName(name, ctx as IMidwayKoaContext);
46
- }
47
- } else {
48
- // 全量刷新:刷新所有已注册的业务缓存
49
- await cacheServiceFactory.refreshAllCache(ctx as IMidwayKoaContext);
50
- }
51
- };
52
- }
53
-
54
- /**
55
- * 缓存类别刷新中间件
56
- *
57
- * 通过 CacheRefreshHub 刷新指定类别的缓存(TableMeta / LinkToCustom / ProxyApiRoute 等)。
58
- * 适用于非 CacheNameEnum 管理的缓存类别。
59
- *
60
- * 使用示例:
61
- * ```typescript
62
- * @Post('/createProxyApi', { middleware: [checkPermission('write'), refreshCategory(CacheRefreshCategory.ProxyApiRoute)] })
63
- * async createProxyApi() { ... }
64
- * ```
65
- *
66
- * @param category 缓存类别,支持单个或数组
67
- */
68
- function refreshCategory(category: CacheRefreshCategory | CacheRefreshCategory[]) {
69
- const categories = Array.isArray(category) ? category : [category];
70
-
71
- return async (ctx: Context, next: NextFunction) => {
72
- await next();
73
-
74
- for (const cat of categories) {
75
- await CacheRefreshHub.refresh(cat, ctx as IMidwayKoaContext);
12
+ const redisService = await ctx.requestContext.getAsync(RedisService);
13
+ for (const key of cacheKeys) {
14
+ await bizMemCacheStore.markDirty(key, redisService);
76
15
  }
77
16
  };
78
17
  }
79
18
 
80
- export { refreshCache, refreshCategory };
19
+ export { refreshBizMemCache };
@@ -1,24 +1,7 @@
1
- /**
2
- * 缓存刷新类型枚举
3
- *
4
- * 用于统一标识项目中的各类缓存,支持:
5
- * - 定时刷新(10分钟自动刷新)
6
- * - API 主动刷新(helpers/refreshCache?category=xxx)
7
- * - manage 增删改触发刷新
8
- * - Redis Pub/Sub 集群广播刷新
9
- */
10
1
  export enum CacheRefreshCategory {
11
- /** 表元数据缓存(CrudProTableMetaService 的 metaCache + tableInfoCache) */
12
2
  TableMeta = 'TableMeta',
13
- /** CacheServiceFactory 管理的业务缓存(CacheNameEnum 定义的所有缓存) */
14
3
  CacheService = 'CacheService',
15
- /** linkToCustom 关联枚举缓存(CurdMixByLinkToCustomService 管理的关联数据缓存) */
16
4
  LinkToCustom = 'LinkToCustom',
17
- /** 代理API路由缓存(ProxyApiLoadService 的 RouteTrie + UpstreamMap) */
18
- ProxyApiRoute = 'ProxyApiRoute',
19
- /** CRUD 方法配置缓存(CrudProCachedCfgService 的 methodCache) */
20
- CrudMethodConfig = 'CrudMethodConfig',
21
5
  }
22
6
 
23
- /** 所有缓存刷新类型列表,用于全量刷新 */
24
7
  export const ALL_CACHE_REFRESH_CATEGORIES = Object.values(CacheRefreshCategory);
@@ -95,6 +95,8 @@ export interface IProxyApiEntity extends IApiBaseEntity {
95
95
  pass_real_ip: number; // DONE
96
96
  change_origin: string; // DONE
97
97
  change_host: string; // DONE
98
+ custom_header: string;
99
+ custom_body: string;
98
100
 
99
101
  balanceStrategy: string; // 负载均衡策略
100
102
  targetList: IUpstreamItem[]; // 运行时根据upstream_code计算的
@@ -152,15 +152,7 @@ export interface ICacheService {
152
152
 
153
153
  export enum CacheNameEnum {
154
154
  CurdMixByAccount = 'CurdMixByAccount',
155
- CurdMixByDict = 'CurdMixByDict',
156
155
  CurdMixByLinkToCustom = 'CurdMixByLinkToCustom',
157
- CurdMixByWorkbench = 'CurdMixByWorkbench',
158
- GetSysConfigOne = 'GetSysConfigOne',
159
- GetDataDictItemsByDictCode = 'GetDataDictItemsByDictCode',
160
- GetWorkbenchCachedObj = 'GetWorkbenchCachedObj',
161
- GetSysAppOne = 'GetSysAppOne',
162
- GetSysAppPageOne = 'GetSysAppPageOne',
163
- GetSysMenusList = 'GetSysMenusList',
164
156
  GetFlowConfigOne = 'GetFlowConfigOne',
165
157
 
166
158
  UserSessionBySessionId = 'UserSessionBySessionId', // 只能是Redis
@@ -1,13 +1,15 @@
1
1
  const INNER_SCHEDULE_INTERVAL = {
2
- cacheRefreshHubScheduleService: 10 * 60 * 1000, // 10分钟刷新一次所有缓存
3
- visitStatService: 10 * 60 * 1000, // 10分钟重新加载一次访问统计
4
- asyncTaskRunnerService: 1000, // 1s可以执行
2
+ cacheRefreshHubScheduleService: 10 * 60 * 1000,
3
+ visitStatService: 10 * 60 * 1000,
4
+ asyncTaskRunnerService: 1000,
5
+ bizMemCacheService: 1000,
5
6
  };
6
7
 
7
8
  const INNER_SCHEDULE_NAMES = {
8
9
  cacheRefreshHubScheduleService: 'cacheRefreshHubScheduleService',
9
10
  visitStatService: 'visitStatService',
10
11
  asyncTaskRunnerService: 'asyncTaskRunnerService',
12
+ bizMemCacheService: 'bizMemCacheService',
11
13
  };
12
14
 
13
15
  export { INNER_SCHEDULE_INTERVAL, INNER_SCHEDULE_NAMES };
@@ -1,39 +1,11 @@
1
- import { Inject, Provide } from '@midwayjs/core';
2
- import { SystemTables } from '@/models/SystemTables';
1
+ import { Provide } from '@midwayjs/core';
3
2
  import { BaseService } from './base/BaseService';
4
- import { CurdProService } from './curd/CurdProService';
5
- import { GLOBAL_STATIC_CONFIG } from '@/libs/global-config/global-config';
6
- import { CacheServiceFactory } from "@/service/base/cache/CacheServiceFactory";
7
- import { CacheNameEnum } from "@/models/bizmodels";
3
+ import { bizMemCacheStore } from '@/service/base/bizmemcache/BizMemCacheStore';
4
+ import { buildSysAppPageCacheKey } from '@/service/base/bizmemcache/BizMemCacheTypes';
8
5
 
9
6
  @Provide()
10
7
  export class SysAppService extends BaseService {
11
8
 
12
- @Inject()
13
- private curdProService: CurdProService;
14
-
15
- @Inject()
16
- private cacheServiceFactory: CacheServiceFactory;
17
-
18
- private get sysAppDao() {
19
- const { SystemDbName, SystemDbType } = GLOBAL_STATIC_CONFIG.getConfig();
20
- return this.curdProService.getQuickCrud({
21
- sqlDatabase: SystemDbName,
22
- sqlDbType: SystemDbType,
23
- sqlTable: SystemTables.sys_app,
24
- })
25
- }
26
-
27
- private get sysAppPageDao() {
28
- const { SystemDbName, SystemDbType } = GLOBAL_STATIC_CONFIG.getConfig();
29
- return this.curdProService.getQuickCrud({
30
- sqlDatabase: SystemDbName,
31
- sqlDbType: SystemDbType,
32
- sqlTable: SystemTables.sys_app_page,
33
- })
34
- }
35
-
36
-
37
9
  async getSysAppPageOne({ page_path, workbench_code }: { page_path: string, workbench_code: string }): Promise<Record<string, any>> {
38
10
  if (!page_path || typeof page_path !== 'string') {
39
11
  throw new Error('[getSysAppPageOne] page_path required');
@@ -41,17 +13,8 @@ export class SysAppService extends BaseService {
41
13
  if (!workbench_code || typeof workbench_code !== 'string') {
42
14
  throw new Error('[getSysAppPageOne] workbench_code required');
43
15
  }
44
- return await this.cacheServiceFactory.getJsonObjectCache({
45
- cacheKey: `${workbench_code}#${page_path}`,
46
- cacheName: CacheNameEnum.GetSysAppPageOne,
47
- getter: async (ctx) => {
48
- const service: SysAppService = await ctx.requestContext.getAsync(SysAppService);
49
- const res = await service.sysAppPageDao.findOne({
50
- condition: { page_path, workbench_code, deleted_at: 0 }
51
- });
52
- return res.row;
53
- },
54
- });
16
+ const sysAppPageMap = bizMemCacheStore.getSysAppPage()?.sysAppPageMap || {};
17
+ return sysAppPageMap[buildSysAppPageCacheKey(workbench_code, page_path)];
55
18
  }
56
19
 
57
20
 
@@ -59,17 +22,8 @@ export class SysAppService extends BaseService {
59
22
  if (!app_code || typeof app_code !== 'string') {
60
23
  throw new Error('[getSysAppOne] app_code required');
61
24
  }
62
- return await this.cacheServiceFactory.getJsonObjectCache({
63
- cacheKey: app_code,
64
- cacheName: CacheNameEnum.GetSysAppOne,
65
- getter: async (ctx) => {
66
- const service: SysAppService = await ctx.requestContext.getAsync(SysAppService);
67
- const res = await service.sysAppDao.findOne({
68
- condition: { app_code, deleted_at: 0 }
69
- });
70
- return res.row;
71
- },
72
- });
25
+ const sysAppCodeMap = bizMemCacheStore.getSysApp()?.sysAppCodeMap || {};
26
+ return sysAppCodeMap[app_code];
73
27
  }
74
28
 
75
29
  public deletePrivateField(parsedAppInfo: any) {
@@ -92,25 +46,18 @@ export class SysAppService extends BaseService {
92
46
  if (!app_code || typeof app_code !== 'string') {
93
47
  throw new Error('[removeSysAppOneCache] app_code required');
94
48
  }
95
- return await this.cacheServiceFactory.removeItemCache({
96
- cacheKey: app_code,
97
- cacheName: CacheNameEnum.GetSysAppOne
98
- });
49
+ await bizMemCacheStore.markDirty('sysAppCacheObj', this.redisService);
99
50
  }
100
51
 
52
+ async removeSysAppPageCache() {
53
+ await bizMemCacheStore.markDirty('sysAppPageCacheObj', this.redisService);
54
+ }
101
55
 
102
- async removeSysAppCacheByCondition({condition} : any){
56
+ async removeSysAppCacheByCondition({ condition }: any) {
103
57
  if (!condition) {
104
58
  throw new Error('[removeSysAppCacheByCondition] condition required');
105
59
  }
106
- const res = await this.sysAppDao.findList({
107
- condition: { ...condition, deleted_at: 0 },
108
- columns: ['id','app_code']
109
- });
110
- const appList = res.rows;
111
- for (const app of appList) {
112
- await this.removeSysAppOneCache(app.app_code);
113
- }
60
+ await bizMemCacheStore.markDirty('sysAppCacheObj', this.redisService);
114
61
  }
115
62
 
116
63
  }