midway-fatcms 0.0.1-beta.13 → 0.0.1-beta.16

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 (86) hide show
  1. package/README.md +7 -0
  2. package/dist/configuration.d.ts +1 -0
  3. package/dist/configuration.js +21 -8
  4. package/dist/controller/base/BaseApiController.d.ts +1 -1
  5. package/dist/controller/gateway/AsyncTaskController.js +17 -6
  6. package/dist/controller/gateway/CrudMtdGatewayController.d.ts +3 -3
  7. package/dist/controller/gateway/CrudMtdGatewayController.js +5 -5
  8. package/dist/index.d.ts +7 -0
  9. package/dist/index.js +7 -0
  10. package/dist/libs/crud-pro/CrudPro.d.ts +1 -0
  11. package/dist/libs/crud-pro/CrudPro.js +5 -0
  12. package/dist/libs/crud-pro/defaultConfigs.js +2 -0
  13. package/dist/libs/crud-pro/interfaces.d.ts +6 -0
  14. package/dist/libs/crud-pro/models/ExecuteContext.d.ts +2 -1
  15. package/dist/libs/crud-pro/models/ExecuteContextFunc.d.ts +8 -1
  16. package/dist/libs/crud-pro/models/ExecuteContextFunc.js +8 -0
  17. package/dist/libs/crud-pro/models/ResModel.d.ts +16 -0
  18. package/dist/libs/crud-pro/models/ResModel.js +2 -0
  19. package/dist/libs/crud-pro/services/CrudProCachedCfgService.d.ts +1 -0
  20. package/dist/libs/crud-pro/services/CrudProCachedCfgService.js +22 -11
  21. package/dist/libs/crud-pro/services/CrudProServiceBase.d.ts +2 -6
  22. package/dist/libs/crud-pro/services/CrudProServiceBase.js +3 -2
  23. package/dist/libs/crud-pro/services/CrudProTableMetaService.d.ts +1 -0
  24. package/dist/libs/crud-pro/services/CrudProTableMetaService.js +31 -7
  25. package/dist/libs/crud-pro/utils/DatabaseName.js +24 -3
  26. package/dist/libs/global-config/global-config.d.ts +6 -0
  27. package/dist/libs/global-config/global-config.js +1 -0
  28. package/dist/models/AsyncTaskModel.d.ts +13 -11
  29. package/dist/models/AsyncTaskModel.js +23 -23
  30. package/dist/schedule/anonymousContext.d.ts +13 -0
  31. package/dist/schedule/anonymousContext.js +59 -0
  32. package/dist/schedule/index.d.ts +4 -4
  33. package/dist/schedule/index.js +9 -68
  34. package/dist/schedule/runSchedule.d.ts +6 -0
  35. package/dist/schedule/runSchedule.js +34 -0
  36. package/dist/schedule/scheduleNames.d.ts +8 -0
  37. package/dist/schedule/scheduleNames.js +17 -0
  38. package/dist/service/asyncTask/AsyncTaskRunnerService.d.ts +14 -0
  39. package/dist/service/asyncTask/AsyncTaskRunnerService.js +66 -16
  40. package/dist/service/asyncTask/AsyncTaskService.js +2 -1
  41. package/dist/service/crudstd/CrudStdService.d.ts +1 -0
  42. package/dist/service/crudstd/CrudStdService.js +27 -0
  43. package/dist/service/curd/CrudProQuick.d.ts +24 -0
  44. package/dist/service/curd/CrudProQuick.js +105 -0
  45. package/dist/service/curd/CurdMixByLinkToCustomService.d.ts +10 -1
  46. package/dist/service/curd/CurdMixByLinkToCustomService.js +71 -23
  47. package/dist/service/curd/CurdMixService.d.ts +1 -1
  48. package/dist/service/curd/CurdMixService.js +2 -2
  49. package/dist/service/curd/CurdMixUtils.js +35 -28
  50. package/dist/service/curd/CurdProService.d.ts +2 -10
  51. package/dist/service/curd/CurdProService.js +28 -143
  52. package/dist/service/curd/fixCfgModel.d.ts +3 -0
  53. package/dist/service/curd/fixCfgModel.js +107 -0
  54. package/package.json +1 -1
  55. package/src/configuration.ts +30 -10
  56. package/src/controller/gateway/AnyApiGatewayController.ts +1 -1
  57. package/src/controller/gateway/AsyncTaskController.ts +21 -8
  58. package/src/controller/gateway/CrudMtdGatewayController.ts +5 -5
  59. package/src/controller/manage/DocManageApi.ts +5 -5
  60. package/src/index.ts +7 -0
  61. package/src/libs/crud-pro/CrudPro.ts +8 -0
  62. package/src/libs/crud-pro/defaultConfigs.ts +2 -0
  63. package/src/libs/crud-pro/interfaces.ts +10 -1
  64. package/src/libs/crud-pro/models/ExecuteContext.ts +5 -2
  65. package/src/libs/crud-pro/models/ExecuteContextFunc.ts +12 -1
  66. package/src/libs/crud-pro/models/ResModel.ts +24 -0
  67. package/src/libs/crud-pro/services/CrudProCachedCfgService.ts +26 -17
  68. package/src/libs/crud-pro/services/CrudProServiceBase.ts +5 -8
  69. package/src/libs/crud-pro/services/CrudProTableMetaService.ts +43 -9
  70. package/src/libs/crud-pro/utils/DatabaseName.ts +35 -15
  71. package/src/libs/global-config/global-config.ts +12 -1
  72. package/src/models/AsyncTaskModel.ts +14 -11
  73. package/src/schedule/anonymousContext.ts +79 -0
  74. package/src/schedule/index.ts +13 -72
  75. package/src/schedule/runSchedule.ts +35 -0
  76. package/src/schedule/scheduleNames.ts +20 -0
  77. package/src/service/asyncTask/AsyncTaskRunnerService.ts +91 -24
  78. package/src/service/asyncTask/AsyncTaskService.ts +3 -2
  79. package/src/service/base/BaseService.ts +2 -2
  80. package/src/service/crudstd/CrudStdService.ts +34 -6
  81. package/src/service/curd/CrudProQuick.ts +137 -0
  82. package/src/service/curd/CurdMixByLinkToCustomService.ts +100 -49
  83. package/src/service/curd/CurdMixService.ts +3 -3
  84. package/src/service/curd/CurdMixUtils.ts +51 -38
  85. package/src/service/curd/CurdProService.ts +42 -186
  86. package/src/service/curd/fixCfgModel.ts +139 -0
@@ -1,6 +1,8 @@
1
1
  import { CrudProServiceBase } from './CrudProServiceBase';
2
2
  import { SqlCfgModel } from '../models/SqlCfgModel';
3
- import { ITableMeta } from '../interfaces';
3
+ import { IExecuteUnsafeQueryCtx, ITableMeta } from '../interfaces';
4
+ import { SqlDbType } from '../models/keys';
5
+ import { pickAndConvertPgRows } from '../utils/sqlConvert/convertPgType';
4
6
 
5
7
  class CrudProTableMetaCache {
6
8
  private cacheMap: Record<string, ITableMeta> = {};
@@ -42,18 +44,50 @@ class CrudProTableMetaService extends CrudProServiceBase {
42
44
  tableColumns: [],
43
45
  };
44
46
 
45
- const baseInfo = {
46
- tableName: sqlCfgModel.sqlTable,
47
- dbName: sqlCfgModel.sqlDatabase,
47
+ const baseInfo: IExecuteUnsafeQueryCtx = {
48
+ sqlTable: sqlCfgModel.sqlTable,
49
+ sqlDatabase: sqlCfgModel.sqlDatabase,
50
+ sqlDbType: sqlCfgModel.sqlDbType
48
51
  };
49
52
 
50
- const [tableDescribe] = await this.executeUnsafeQuery(baseInfo, 'describe ' + sqlCfgModel.sqlTable);
51
- const tableDescribe2 = JSON.parse(JSON.stringify(tableDescribe));
52
- obj.tableColumns = tableDescribe2.map(fieldObj => {
53
- return fieldObj['Field'];
54
- });
53
+ obj.tableColumns = await this.loadTableColumnInfo(baseInfo);
54
+
55
55
  return obj;
56
56
  }
57
+
58
+
59
+
60
+ private async loadTableColumnInfo(baseInfo: IExecuteUnsafeQueryCtx): Promise<string[]>{
61
+
62
+ if(baseInfo.sqlDbType === SqlDbType.mysql) {
63
+ const [tableDescribe] = await this.executeUnsafeQuery(baseInfo, 'describe ' + baseInfo.sqlTable);
64
+ const tableDescribe2 = JSON.parse(JSON.stringify(tableDescribe));
65
+ return tableDescribe2.map(fieldObj => {
66
+ return fieldObj['Field'];
67
+ });
68
+ }
69
+
70
+ else if(baseInfo.sqlDbType === SqlDbType.postgres) {
71
+ const schemaname = 'public';
72
+ const columnArraySql = `
73
+ SELECT
74
+ *
75
+ FROM information_schema.columns
76
+ WHERE table_schema = '${schemaname}' and table_name = '${baseInfo.sqlTable}'
77
+ ORDER BY ordinal_position;
78
+ `.trim();
79
+ const queryRes = await this.executeUnsafeQuery(baseInfo, columnArraySql);
80
+ const rows = pickAndConvertPgRows(queryRes)
81
+ return rows.map(fieldObj => {
82
+ return fieldObj['column_name'];
83
+ });
84
+ }
85
+
86
+
87
+ throw new Error("暂不支持的数据库类型:" + baseInfo.sqlDbType)
88
+ }
89
+
90
+
57
91
  }
58
92
 
59
93
  export { CrudProTableMetaService };
@@ -1,19 +1,45 @@
1
- import { SqlDbType } from '../models/keys'
1
+ import { SqlDbType } from '../models/keys';
2
2
 
3
3
  interface IDbTypeAndName {
4
- dbType: SqlDbType,
4
+ dbType: SqlDbType;
5
5
  dbName: string;
6
6
  }
7
7
 
8
- const SPLIT_CONST = "_________"
8
+ const SPLIT_CONST = '_________';
9
+
10
+ const PREFIX_MYSQL = `${SqlDbType.mysql}${SPLIT_CONST}`;
11
+ const PREFIX_POSTGRES = `${SqlDbType.postgres}${SPLIT_CONST}`;
12
+ const PREFIX_SQLSERVER = `${SqlDbType.sqlserver}${SPLIT_CONST}`;
9
13
 
10
14
  function parseDatabaseName(databaseName: string): IDbTypeAndName {
11
15
  const dbNameArr = databaseName.split(SPLIT_CONST);
16
+
17
+ if (databaseName.startsWith(PREFIX_MYSQL)) {
18
+ return {
19
+ dbType: SqlDbType.mysql,
20
+ dbName: dbNameArr[1],
21
+ };
22
+ }
23
+
24
+ if (databaseName.startsWith(PREFIX_POSTGRES)) {
25
+ return {
26
+ dbType: SqlDbType.postgres,
27
+ dbName: dbNameArr[1],
28
+ };
29
+ }
30
+
31
+ if (databaseName.startsWith(PREFIX_SQLSERVER)) {
32
+ return {
33
+ dbType: SqlDbType.sqlserver,
34
+ dbName: dbNameArr[1],
35
+ };
36
+ }
37
+
12
38
  if (dbNameArr.length === 1) {
13
39
  return {
14
40
  dbType: SqlDbType.mysql, // 默认
15
- dbName: dbNameArr[0]
16
- }
41
+ dbName: dbNameArr[0],
42
+ };
17
43
  }
18
44
 
19
45
  if (dbNameArr.length > 1) {
@@ -21,20 +47,14 @@ function parseDatabaseName(databaseName: string): IDbTypeAndName {
21
47
  const dbType = dbType0 as any;
22
48
  return {
23
49
  dbType,
24
- dbName
25
- }
50
+ dbName,
51
+ };
26
52
  }
27
53
  return null;
28
54
  }
29
55
 
30
-
31
56
  function toDatabaseNameStr(dbType: SqlDbType, dbName: string): string {
32
- return [dbType, dbName].join(SPLIT_CONST)
57
+ return [dbType, dbName].join(SPLIT_CONST);
33
58
  }
34
59
 
35
-
36
- export {
37
- SPLIT_CONST,
38
- parseDatabaseName,
39
- toDatabaseNameStr
40
- }
60
+ export { SPLIT_CONST, parseDatabaseName, toDatabaseNameStr };
@@ -20,9 +20,19 @@ interface IGlobalStaticConfig {
20
20
  bizUpdateCfgModelForCrudMtd(reqJson: any, cfgModel: any, methodInfo: any, ctx: any): Promise<any>;
21
21
 
22
22
 
23
+
24
+ /**
25
+ * CrudPro: 业务系统自定义的修改cfgModel。这是最底层的!!全局的!!全局的!!全局的!!!
26
+ * @param reqJson
27
+ * @param cfgModel
28
+ */
29
+ bizUpdateCfgModelForCrudPro(reqJson: any, cfgModel: any): Promise<any>;
30
+
31
+
32
+
23
33
  /**
24
34
  * 生成用户的账号ID,业务系统可以生成类似工号的ID
25
- * @param userSubmitData
35
+ * @param userSubmitData
26
36
  */
27
37
  generateUserAccountId(userSubmitData: any): Promise<string>;
28
38
 
@@ -47,6 +57,7 @@ class GlobalStaticConfig {
47
57
  this.configObject = {
48
58
  bizUpdateCfgModelForCrudStd: noop,
49
59
  bizUpdateCfgModelForCrudMtd: noop,
60
+ bizUpdateCfgModelForCrudPro: noop,
50
61
  generateUserAccountId: null,
51
62
  toFatcmsUserAccountId: (bizTableUserId: any) => {
52
63
  return bizTableUserId;
@@ -4,16 +4,16 @@ export interface SysAsyncTaskEntity {
4
4
  task_name: string;
5
5
  task_description: string | null;
6
6
  task_type: string;
7
- task_status: TaskStatus;
7
+ task_status: SysAsyncTaskStatus;
8
8
  input_params: any;
9
9
  output_result: any | null;
10
10
 
11
11
  input_file_path: string | null;
12
- input_file_format: FileFormat | null;
12
+ input_file_format: SysAsyncFileFormat | null;
13
13
  input_file_size: number | null;
14
14
 
15
15
  output_file_path: string | null;
16
- output_file_format: FileFormat | null;
16
+ output_file_format: SysAsyncFileFormat | null;
17
17
  output_file_size: number | null;
18
18
 
19
19
  input_total_records: number | null;
@@ -26,15 +26,17 @@ export interface SysAsyncTaskEntity {
26
26
  priority: number;
27
27
  retry_count: number;
28
28
  max_retries: number;
29
+
29
30
  parent_task_id: number | null;
30
31
  created_at: Date;
31
32
  started_at: Date | null;
32
- completed_at: Date | null;
33
33
  updated_at: Date;
34
34
  expired_at: Date | null;
35
+ completed_at: Date | null;
36
+ created_user_session: string;
35
37
  }
36
38
 
37
- export enum TaskStatus {
39
+ export enum SysAsyncTaskStatus {
38
40
  PENDING = 'PENDING', // 等待中,还未进入排队
39
41
  RUNNING = 'RUNNING', // 运行中
40
42
  SUCCEEDED = 'SUCCEEDED',
@@ -43,7 +45,7 @@ export enum TaskStatus {
43
45
  PAUSED = 'PAUSED', // 暂停
44
46
  }
45
47
 
46
- export enum FileFormat {
48
+ export enum SysAsyncFileFormat {
47
49
  XLSX = 'xlsx',
48
50
  CSV = 'csv',
49
51
  JSON = 'json',
@@ -57,17 +59,18 @@ export enum FileFormat {
57
59
  }
58
60
 
59
61
 
60
- export interface ITaskHandler {
61
- execute(ctx: TaskContext): Promise<void>;
62
+ export interface ISysAsyncTaskHandler {
63
+ execute(asyncTaskContext: SysAsyncTaskContext): Promise<void>;
62
64
  }
63
65
 
64
- export interface TaskContext {
66
+ export interface SysAsyncTaskContext {
65
67
  task: SysAsyncTaskEntity;
68
+ updateTaskStatus: ()=>any;
66
69
  }
67
70
 
68
- export interface TaskHandlerConfig {
71
+ export interface SysAsyncTaskHandlerConfig {
69
72
  taskType: string;
70
- handler: ITaskHandler;
73
+ handler: ISysAsyncTaskHandler;
71
74
  maxRetries?: number;
72
75
  priority?: number;
73
76
  expireSeconds?: number;
@@ -0,0 +1,79 @@
1
+ import * as koa from '@midwayjs/koa';
2
+ import {ContextLogger} from "@/models/contextLogger";
3
+ import {Transaction} from "@/libs/crud-pro/models/Transaction";
4
+ import {ISessionInfo, SYS_ACCOUNT_TYPE, UserSessionInfo} from "@/models/userSession";
5
+ import {IWorkbenchEntity} from "@/models/SystemEntities";
6
+
7
+
8
+ const anonymousUserInfo:ISessionInfo = {
9
+ nickName: 'anonymous_user',
10
+ avatar: '',
11
+ roleCodes: [],
12
+ functionCodes: [],
13
+ loginName: 'anonymous_user',
14
+ sessionId: '',
15
+ accountId: '',
16
+ workbenchCode: '',
17
+ accountType: SYS_ACCOUNT_TYPE,
18
+ };
19
+
20
+ const anonymousWorkbenchInfo: IWorkbenchEntity = {
21
+ id: 0,
22
+ workbench_code: 'anonymous_workbench',
23
+ workbench_name: 'anonymous_workbench',
24
+ workbench_domain: 'anonymous_workbench',
25
+ workbench_desc: 'anonymous_workbench',
26
+ html_content: 'anonymous_workbench',
27
+ status: 1,
28
+ workbench_type: 0,
29
+ };
30
+
31
+
32
+ export type RunServiceAtAnonymousContextRunner = (ctx: koa.IMidwayKoaContext)=>any;
33
+
34
+
35
+ class AnonymousContext {
36
+ private app: koa.Application;
37
+
38
+ setApp(app: koa.Application){
39
+ this.app = app;
40
+ }
41
+
42
+ getApp(){
43
+ return this.app;
44
+ }
45
+
46
+
47
+ async runServiceAtAnonymousContext( runner: RunServiceAtAnonymousContextRunner) {
48
+ const app = this.app;
49
+ const ctx: koa.IMidwayKoaContext = app.createAnonymousContext();
50
+
51
+ ctx.app = app;
52
+ ctx.contextLogger = new ContextLogger(ctx as any);
53
+ ctx.transaction = new Transaction();
54
+ ctx.userSession = new UserSessionInfo(anonymousUserInfo, true);
55
+ ctx.workbenchInfo = anonymousWorkbenchInfo;
56
+
57
+ let result: any = null;
58
+ let error: any = null;
59
+ try {
60
+ result = await runner(ctx);
61
+ } catch (e) {
62
+ error = e;
63
+ ctx.logger.error(`runServiceAtAnonymousContext error `, e);
64
+ } finally {
65
+ await ctx.transaction.releaseTx();
66
+ }
67
+ return {result: result, error: error};
68
+ }
69
+
70
+ }
71
+
72
+
73
+ const ANONYMOUS_CONTEXT = new AnonymousContext()
74
+
75
+
76
+
77
+ export {
78
+ ANONYMOUS_CONTEXT
79
+ }
@@ -1,73 +1,14 @@
1
- import * as koa from '@midwayjs/koa';
2
- import { IScheduleService } from '../interface';
3
- import { ContextLogger } from '../models/contextLogger';
4
- import { Transaction } from '../libs/crud-pro/models/Transaction';
5
- import {ISessionInfo, SYS_ACCOUNT_TYPE, UserSessionInfo} from '../models/userSession';
6
- import { IWorkbenchEntity } from '../models/SystemEntities';
7
-
8
- const scheduleUserInfo:ISessionInfo = {
9
- nickName: 'schedule_user',
10
- avatar: '',
11
- roleCodes: [],
12
- functionCodes: [],
13
- loginName: 'schedule_user',
14
- sessionId: '',
15
- accountId: '',
16
- workbenchCode: '',
17
- accountType: SYS_ACCOUNT_TYPE,
18
- };
19
-
20
- const scheduleWorkbenchInfo: IWorkbenchEntity = {
21
- id: 0,
22
- workbench_code: 'schedule_workbench',
23
- workbench_name: 'schedule_workbench',
24
- workbench_domain: 'schedule_workbench',
25
- workbench_desc: 'schedule_workbench',
26
- html_content: 'schedule_workbench',
27
- status: 1,
28
- workbench_type: 0,
29
- };
30
-
31
- async function runScheduleService(app: koa.Application, serviceName: string) {
32
- const ctx = app.createAnonymousContext();
33
-
34
- ctx.app = app;
35
- ctx.contextLogger = new ContextLogger(ctx as any);
36
- ctx.transaction = new Transaction();
37
- ctx.userSession = new UserSessionInfo(scheduleUserInfo, true);
38
- ctx.workbenchInfo = scheduleWorkbenchInfo;
39
-
40
- try {
41
- const serviceObject: IScheduleService = await ctx.requestContext.getAsync(serviceName);
42
- if (serviceObject && serviceObject.runBySchedule) {
43
- await serviceObject.runBySchedule();
44
- } else {
45
- ctx.logger.error(`runSchedule error , serviceName = ${serviceName}, 没有找到服务`);
46
- }
47
- } catch (e) {
48
- ctx.logger.error(`runSchedule error , serviceName = ${serviceName}`, e);
49
- } finally {
50
- await ctx.transaction.releaseTx();
51
- }
1
+ import {startScheduleLoop, runScheduleTaskOnce} from './runSchedule'
2
+ import {ANONYMOUS_CONTEXT} from './anonymousContext'
3
+ import {
4
+ ALL_SCHEDULE_NAMES,
5
+ SCHEDULE_NAMES,
6
+ } from './scheduleNames'
7
+
8
+ export {
9
+ ALL_SCHEDULE_NAMES,
10
+ SCHEDULE_NAMES,
11
+ ANONYMOUS_CONTEXT,
12
+ startScheduleLoop,
13
+ runScheduleTaskOnce
52
14
  }
53
-
54
- async function runSchedule(app: koa.Application, serviceList: string[]) {
55
- for (let i = 0; i < serviceList.length; i++) {
56
- const serviceName = serviceList[i];
57
- try {
58
- await runScheduleService(app, serviceName);
59
- } catch (e) {
60
- const ctx = app.createAnonymousContext();
61
- ctx.logger.error(`runSchedule error , serviceName = ${serviceName}`, e);
62
- }
63
- }
64
- }
65
-
66
- async function startSchedule(app: koa.Application, serviceList: string[]) {
67
- await runSchedule(app, serviceList);
68
- setInterval(() => {
69
- runSchedule(app, serviceList);
70
- }, 2 * 60 * 1000);
71
- }
72
-
73
- export { startSchedule, runSchedule };
@@ -0,0 +1,35 @@
1
+ import * as koa from '@midwayjs/koa';
2
+ import { IScheduleService } from '@/interface';
3
+ import { ANONYMOUS_CONTEXT } from "./anonymousContext";
4
+
5
+
6
+ async function runScheduleTaskOnce(serviceName: string) {
7
+ return await ANONYMOUS_CONTEXT.runServiceAtAnonymousContext(async (ctx: koa.IMidwayKoaContext)=>{
8
+ const serviceObject: IScheduleService = await ctx.requestContext.getAsync(serviceName);
9
+ if (serviceObject && serviceObject.runBySchedule) {
10
+ await serviceObject.runBySchedule();
11
+ } else {
12
+ ctx.logger.error(`runSchedule error , serviceName = ${serviceName}, 没有找到服务`);
13
+ }
14
+ });
15
+ }
16
+
17
+ async function runScheduleServiceList(serviceList: string[]) {
18
+ for (let i = 0; i < serviceList.length; i++) {
19
+ const serviceName = serviceList[i];
20
+ try {
21
+ await runScheduleTaskOnce(serviceName);
22
+ } catch (e) {
23
+ ANONYMOUS_CONTEXT.getApp().getCoreLogger().error(`runSchedule error , serviceName = ${serviceName}`, e);
24
+ }
25
+ }
26
+ }
27
+
28
+ async function startScheduleLoop(serviceList: string[]) {
29
+ await runScheduleServiceList(serviceList);
30
+ setInterval(() => {
31
+ runScheduleServiceList(serviceList);
32
+ }, 2 * 60 * 1000);
33
+ }
34
+
35
+ export { startScheduleLoop, runScheduleTaskOnce };
@@ -0,0 +1,20 @@
1
+
2
+
3
+ const SCHEDULE_NAMES = {
4
+ proxyApiLoadService: 'proxyApiLoadService',
5
+ workbenchService: 'workbenchService',
6
+ visitStatService: 'visitStatService',
7
+ asyncTaskRunnerService: 'asyncTaskRunnerService',
8
+ }
9
+
10
+ const ALL_SCHEDULE_NAMES = [
11
+ SCHEDULE_NAMES.proxyApiLoadService,
12
+ SCHEDULE_NAMES.workbenchService,
13
+ SCHEDULE_NAMES.visitStatService,
14
+ SCHEDULE_NAMES.asyncTaskRunnerService
15
+ ];
16
+
17
+ export {
18
+ ALL_SCHEDULE_NAMES,
19
+ SCHEDULE_NAMES,
20
+ }
@@ -1,36 +1,47 @@
1
1
  import {Inject, Provide} from '@midwayjs/core';
2
- import {Context} from '@midwayjs/koa';
2
+ import {Context, IMidwayKoaContext} from '@midwayjs/koa';
3
3
  import {BaseService} from "@/service/base/BaseService";
4
4
  import {IScheduleService} from "@/interface";
5
5
  import {CurdProService} from "@/service/curd/CurdProService";
6
- import {ITaskHandler, SysAsyncTaskEntity, TaskStatus} from "@/models/AsyncTaskModel";
6
+ import {ISysAsyncTaskHandler, SysAsyncTaskEntity, SysAsyncTaskStatus} from "@/models/AsyncTaskModel";
7
7
  import {GLOBAL_STATIC_CONFIG} from "@/libs/global-config/global-config";
8
8
  import {SystemTables} from "@/models/SystemTables";
9
9
  import {KeysOfSimpleSQL} from "@/libs/crud-pro/models/keys";
10
10
  import {errorToString} from "@/libs/utils/errorToString";
11
+ import {ANONYMOUS_CONTEXT} from "@/schedule";
11
12
 
12
13
 
13
- class AsyncTaskRunner {
14
+ class AsyncTaskRunner {
14
15
  isBusy: boolean = false;
15
- taskHandlerMap: Map<string, ITaskHandler> = new Map();
16
+ taskHandlerMap: Map<string, ISysAsyncTaskHandler> = new Map();
16
17
 
17
18
  async executeTaskList(taskList: SysAsyncTaskEntity[]) {
18
19
  if (!taskList || taskList.length === 0) {
19
20
  return;
20
21
  }
22
+
21
23
  this.isBusy = true;
22
24
 
23
25
  for (let i = 0; i < taskList.length; i++) {
24
26
  const taskElement = taskList[i];
27
+
25
28
  try {
29
+ // 任务状态的设置在自定义的执行器里面。
26
30
  await this.executeTask(taskElement);
27
- taskElement.task_status = TaskStatus.SUCCEEDED;
28
31
  } catch (error) {
29
- taskElement.task_status = TaskStatus.FAILED;
32
+ taskElement.task_status = SysAsyncTaskStatus.FAILED;
30
33
  taskElement.error_message = errorToString(error)
31
34
  }
35
+
36
+ try {
37
+ await this.updateTaskStatus(taskElement);
38
+ } catch (error) {
39
+ ANONYMOUS_CONTEXT.getApp().getCoreLogger().error("executeTaskList error", error);
40
+ }
32
41
  }
33
42
 
43
+ this.isBusy = false;
44
+
34
45
  }
35
46
 
36
47
  private async executeTask(taskElement: SysAsyncTaskEntity) {
@@ -39,18 +50,52 @@ class AsyncTaskRunner {
39
50
  if (!taskHandler) {
40
51
  throw new Error('TaskHandler not found , taskType = ' + taskType);
41
52
  }
42
- await taskHandler.execute({task: taskElement});
53
+ const updateTaskStatus = () => {
54
+ return this.updateTaskStatus(taskElement);
55
+ }
56
+ await taskHandler.execute({task: taskElement, updateTaskStatus});
57
+ }
58
+
59
+
60
+ private async updateTaskStatus(taskElement: SysAsyncTaskEntity) {
61
+ return await ANONYMOUS_CONTEXT.runServiceAtAnonymousContext(async (ctx: IMidwayKoaContext) => {
62
+ const curdProService: CurdProService = await ctx.requestContext.getAsync("curdProService");
63
+ const {SystemDbName, SystemDbType} = GLOBAL_STATIC_CONFIG.getConfig();
64
+
65
+ const {id, ...otherTaskProps} = taskElement;
66
+
67
+ const res = await curdProService.executeCrudByCfg({
68
+ condition: {
69
+ id: id
70
+ },
71
+ data: otherTaskProps
72
+ }, {
73
+ sqlTable: SystemTables.sys_async_tasks,
74
+ sqlSimpleName: KeysOfSimpleSQL.SIMPLE_UPDATE,
75
+ sqlDatabase: SystemDbName,
76
+ sqlDbType: SystemDbType,
77
+ });
78
+ return res.getResModel().affected;
79
+ });
80
+
81
+
43
82
  }
44
83
  }
45
84
 
46
85
 
47
- const ASYNC_TASK_RUNNER = new AsyncTaskRunner();
86
+ /**
87
+ * 业务可以扩展
88
+ */
89
+ export const ASYNC_TASK_RUNNER = new AsyncTaskRunner();
48
90
 
49
91
 
92
+ /**
93
+ * Redis锁
94
+ */
50
95
  const LOCK_KEY_ASYNC_TASK_RUNNER = "LOCK_KEY_ASYNC_TASK_RUNNER"
51
96
 
52
97
  @Provide()
53
- export class AsyncTaskRunnerService extends BaseService implements IScheduleService{
98
+ export class AsyncTaskRunnerService extends BaseService implements IScheduleService {
54
99
 
55
100
  @Inject()
56
101
  protected ctx: Context;
@@ -58,31 +103,25 @@ export class AsyncTaskRunnerService extends BaseService implements IScheduleServ
58
103
  @Inject()
59
104
  private curdProService: CurdProService;
60
105
 
61
- async runBySchedule () {
62
- if (ASYNC_TASK_RUNNER.isBusy) {
63
- return Promise.resolve();
64
- }
65
106
 
66
- const lock = await this.redisService.set(LOCK_KEY_ASYNC_TASK_RUNNER, 1,"EX", 3600, "NX");
67
- if (lock !== 'OK') {
68
- return Promise.resolve();
69
- }
107
+ async fetchPendingTasks(): Promise<void> {
70
108
 
71
-
72
- const { SystemDbName, SystemDbType } = GLOBAL_STATIC_CONFIG.getConfig();
109
+ const {SystemDbName, SystemDbType} = GLOBAL_STATIC_CONFIG.getConfig();
73
110
 
74
111
  const queryRes = await this.curdProService.executeCrudByCfg({
75
112
  condition: {
76
- task_status: TaskStatus.PENDING
113
+ task_status: SysAsyncTaskStatus.PENDING
77
114
  },
115
+ orderBy: 'id+',
78
116
  limit: 10
79
- },{
117
+ }, {
80
118
  sqlTable: SystemTables.sys_async_tasks,
81
119
  sqlSimpleName: KeysOfSimpleSQL.SIMPLE_QUERY_PAGE,
82
120
  sqlDatabase: SystemDbName,
83
121
  sqlDbType: SystemDbType,
84
122
  });
85
123
 
124
+
86
125
  const taskList = queryRes.getResRows();
87
126
 
88
127
  if (taskList.length === 0) {
@@ -98,9 +137,9 @@ export class AsyncTaskRunnerService extends BaseService implements IScheduleServ
98
137
  }
99
138
  },
100
139
  data: {
101
- task_status: TaskStatus.RUNNING
140
+ task_status: SysAsyncTaskStatus.RUNNING
102
141
  }
103
- },{
142
+ }, {
104
143
  sqlTable: SystemTables.sys_async_tasks,
105
144
  sqlSimpleName: KeysOfSimpleSQL.SIMPLE_UPDATE,
106
145
  sqlDatabase: SystemDbName,
@@ -108,7 +147,35 @@ export class AsyncTaskRunnerService extends BaseService implements IScheduleServ
108
147
  });
109
148
 
110
149
 
111
- ASYNC_TASK_RUNNER.executeTaskList(taskList);
150
+ ASYNC_TASK_RUNNER.executeTaskList(taskList).then(() => {
151
+ console.log("ASYNC_TASK_RUNNER finished taskIds ==> " + JSON.stringify(taskIds))
152
+ })
153
+
154
+ }
155
+
156
+
157
+ async runBySchedule() {
158
+ if (ASYNC_TASK_RUNNER.isBusy) {
159
+ return Promise.resolve();
160
+ }
161
+
162
+ // 这里的过期时间1分钟即可。fetchPendingTasks函数不可能超过一分钟。
163
+ // 因为这里只是从数据库中获取一批任务,放到自己的任务队列里。还没触发执行。
164
+ const lock = await this.redisService.set(LOCK_KEY_ASYNC_TASK_RUNNER, 1, "EX", 60, "NX");
165
+ if (lock !== 'OK') {
166
+ return Promise.resolve();
167
+ }
168
+
169
+ try {
170
+ await this.fetchPendingTasks();
171
+ } catch (e) {
172
+ console.error("fetchPendingTasks error", errorToString(e));
173
+ }
174
+
175
+ await this.redisService.del(LOCK_KEY_ASYNC_TASK_RUNNER);
176
+
112
177
  return Promise.resolve();
113
178
  }
179
+
180
+
114
181
  }
@@ -1,7 +1,8 @@
1
1
  import {Inject, Provide} from '@midwayjs/core';
2
2
  import {Context} from '@midwayjs/koa';
3
3
  import {BaseService} from "@/service/base/BaseService";
4
- import {runSchedule} from "@/schedule";
4
+ import {runScheduleTaskOnce} from "@/schedule";
5
+ import {SCHEDULE_NAMES} from "@/schedule/scheduleNames";
5
6
 
6
7
  @Provide()
7
8
  export class AsyncTaskService extends BaseService {
@@ -9,7 +10,7 @@ export class AsyncTaskService extends BaseService {
9
10
  protected ctx: Context;
10
11
 
11
12
  async startTask() {
12
- runSchedule(this.app, ['asyncTaskRunnerService']).then(schedule => {
13
+ runScheduleTaskOnce(SCHEDULE_NAMES.asyncTaskRunnerService).then(schedule => {
13
14
  console.log(schedule);
14
15
  })
15
16
  }