midway-fatcms 0.0.1-beta.24 → 0.0.1-beta.25

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.
@@ -1,121 +1,121 @@
1
- import { Inject, Provide } from '@midwayjs/core';
2
- import { Context } from '@midwayjs/koa';
3
- import * as vm from 'node:vm';
4
- import { LRUCache } from 'lru-cache';
5
- import { BaseService } from '../base/BaseService';
6
- import { CurdMixService } from '../curd/CurdMixService';
7
- import { ISysAnyApiEntity } from '../../models/SystemEntities';
8
- import axios from 'axios';
9
- import * as _ from 'lodash';
10
- import * as moment from 'moment';
11
- import * as nodemailer from 'nodemailer';
12
-
13
- const scriptCacheOptions = {
14
- max: 500,
15
- ttl: 1000 * 60 * 5,
16
- allowStale: false,
17
- updateAgeOnGet: true,
18
- updateAgeOnHas: true,
19
- };
20
-
21
- const scriptCache = new LRUCache<string, vm.Script>(scriptCacheOptions);
22
-
23
- function getCompiledScript(anyApi: ISysAnyApiEntity, code: string): vm.Script {
24
- const { id, func_code_md5 } = anyApi;
25
- const cacheKey = id + '_' + func_code_md5;
26
- const oldScript = scriptCache.get(cacheKey);
27
- if (oldScript) {
28
- return oldScript;
29
- }
30
- const script = new vm.Script(code);
31
- scriptCache.set(cacheKey, script);
32
- return script;
33
- }
34
-
35
- export interface IRunInSandboxParams {
36
- body: any;
37
- query: any;
38
- headers: any;
39
- params?: any;
40
- }
41
-
42
- @Provide()
43
- export class AnyApiSandboxService extends BaseService {
44
- @Inject()
45
- protected ctx: Context;
46
-
47
- @Inject()
48
- private curdMixService: CurdMixService;
49
-
50
- public async runInSandbox(anyApi: ISysAnyApiEntity, allParams: IRunInSandboxParams) {
51
- const { func_code, method } = anyApi;
52
-
53
- return new Promise((resolve, reject) => {
54
- const logger = this.getPrefixContextLogger(`[AnyApiSandboxService][method=${method}]`);
55
- // 创建一个沙盒上下文
56
- const proc = process;
57
- const newContext = {
58
- sandbox: {
59
- allParams,
60
- logger,
61
- moment,
62
- axios,
63
- nodemailer,
64
- _,
65
- userSession: this.ctx.userSession,
66
- ctx: this.ctx,
67
- curdMixService: this.curdMixService,
68
- redisService: this.redisService,
69
- publicOSSService: this.getPublicOSSService(),
70
- privateOSSService: this.getPrivateOSSService(),
71
- returnSuccess: resolve,
72
- returnError: reject,
73
- processInfo: {
74
- version: proc.version,
75
- versions: proc.versions,
76
- env: process.env,
77
- argv: process.argv,
78
- cwd: process.cwd(),
79
- },
80
- },
81
- console: logger,
82
- JSON: JSON,
83
- };
84
-
85
- const nextLine100 = new Array(10).fill('\n').join('');
86
- const bindCode = this.toBindCodeString('httpController', newContext, 'sandbox');
87
- const code = `
88
- (async () => {
89
- ${nextLine100}${func_code}; // 必须有一个 class HttpController { async handleRequest(params){} }
90
- ${nextLine100}
91
- try {
92
- const httpController = new HttpController();
93
- ${bindCode}
94
- const res = await httpController.handleRequest(sandbox.allParams.params);
95
- sandbox.returnSuccess(res);
96
- } catch (e) {
97
- sandbox.returnError(e)
98
- }
99
- })(); `;
100
-
101
- try {
102
- const script = getCompiledScript(anyApi, code);
103
- script.runInNewContext(newContext, {
104
- filename: 'method',
105
- timeout: anyApi.timeout_ms || 1000 * 60 * 5,
106
- });
107
- } catch (e) {
108
- reject(e);
109
- }
110
- });
111
- }
112
-
113
- private toBindCodeString(toName: string, newContext: any, fromName: any): string {
114
- const keys = Object.keys(newContext[fromName]);
115
- return keys
116
- .map(key => {
117
- return `${toName}.${key} = ${fromName}.${key};\n`;
118
- })
119
- .join('');
120
- }
121
- }
1
+ import { Inject, Provide } from '@midwayjs/core';
2
+ import { Context } from '@midwayjs/koa';
3
+ import * as vm from 'node:vm';
4
+ import { LRUCache } from 'lru-cache';
5
+ import { BaseService } from '../base/BaseService';
6
+ import { CurdMixService } from '../curd/CurdMixService';
7
+ import { ISysAnyApiEntity } from '../../models/SystemEntities';
8
+ import axios from 'axios';
9
+ import * as _ from 'lodash';
10
+ import * as moment from 'moment';
11
+ import * as nodemailer from 'nodemailer';
12
+
13
+ const scriptCacheOptions = {
14
+ max: 500,
15
+ ttl: 1000 * 60 * 5,
16
+ allowStale: false,
17
+ updateAgeOnGet: true,
18
+ updateAgeOnHas: true,
19
+ };
20
+
21
+ const scriptCache = new LRUCache<string, vm.Script>(scriptCacheOptions);
22
+
23
+ function getCompiledScript(anyApi: ISysAnyApiEntity, code: string): vm.Script {
24
+ const { id, func_code_md5 } = anyApi;
25
+ const cacheKey = id + '_' + func_code_md5;
26
+ const oldScript = scriptCache.get(cacheKey);
27
+ if (oldScript) {
28
+ return oldScript;
29
+ }
30
+ const script = new vm.Script(code);
31
+ scriptCache.set(cacheKey, script);
32
+ return script;
33
+ }
34
+
35
+ export interface IRunInSandboxParams {
36
+ body: any;
37
+ query: any;
38
+ headers: any;
39
+ params?: any;
40
+ }
41
+
42
+ @Provide()
43
+ export class AnyApiSandboxService extends BaseService {
44
+ @Inject()
45
+ protected ctx: Context;
46
+
47
+ @Inject()
48
+ private curdMixService: CurdMixService;
49
+
50
+ public async runInSandbox(anyApi: ISysAnyApiEntity, allParams: IRunInSandboxParams) {
51
+ const { func_code, method } = anyApi;
52
+
53
+ return new Promise((resolve, reject) => {
54
+ const logger = this.getPrefixContextLogger(`[AnyApiSandboxService][method=${method}]`);
55
+ // 创建一个沙盒上下文
56
+ const proc = process;
57
+ const newContext = {
58
+ sandbox: {
59
+ allParams,
60
+ logger,
61
+ moment,
62
+ axios,
63
+ nodemailer,
64
+ _,
65
+ userSession: this.ctx.userSession,
66
+ ctx: this.ctx,
67
+ curdMixService: this.curdMixService,
68
+ redisService: this.redisService,
69
+ publicOSSService: this.getPublicOSSService(),
70
+ privateOSSService: this.getPrivateOSSService(),
71
+ returnSuccess: resolve,
72
+ returnError: reject,
73
+ processInfo: {
74
+ version: proc.version,
75
+ versions: proc.versions,
76
+ env: process.env,
77
+ argv: process.argv,
78
+ cwd: process.cwd(),
79
+ },
80
+ },
81
+ console: logger,
82
+ JSON: JSON,
83
+ };
84
+
85
+ const nextLine100 = new Array(10).fill('\n').join('');
86
+ const bindCode = this.toBindCodeString('httpController', newContext, 'sandbox');
87
+ const code = `
88
+ (async () => {
89
+ ${nextLine100}${func_code}; // 必须有一个 class HttpController { async handleRequest(params){} }
90
+ ${nextLine100}
91
+ try {
92
+ const httpController = new HttpController();
93
+ ${bindCode}
94
+ const res = await httpController.handleRequest(sandbox.allParams.params);
95
+ sandbox.returnSuccess(res);
96
+ } catch (e) {
97
+ sandbox.returnError(e)
98
+ }
99
+ })(); `;
100
+
101
+ try {
102
+ const script = getCompiledScript(anyApi, code);
103
+ script.runInNewContext(newContext, {
104
+ filename: 'method',
105
+ timeout: anyApi.timeout_ms || 1000 * 60 * 5,
106
+ });
107
+ } catch (e) {
108
+ reject(e);
109
+ }
110
+ });
111
+ }
112
+
113
+ private toBindCodeString(toName: string, newContext: any, fromName: any): string {
114
+ const keys = Object.keys(newContext[fromName]);
115
+ return keys
116
+ .map(key => {
117
+ return `${toName}.${key} = ${fromName}.${key};\n`;
118
+ })
119
+ .join('');
120
+ }
121
+ }
@@ -1,187 +1,186 @@
1
- import { Inject, Provide } from '@midwayjs/core';
2
- import { Context } from '@midwayjs/koa';
3
- import { KeysOfSimpleSQL } from '@/libs/crud-pro/models/keys';
4
- import { SystemTables} from '@/models/SystemTables';
5
- import { LRUCache } from 'lru-cache';
6
- import { BizException } from '@/models/devops';
7
- import { CurdMixService } from '../curd/CurdMixService';
8
- import { ISysAnyApiEntity } from '@/models/SystemEntities';
9
- import { AnyApiSandboxService, IRunInSandboxParams } from './AnyApiSandboxService';
10
- import { parseJsonObject } from '@/libs/utils/functions';
11
- import * as _ from 'lodash';
12
- import { MixinUtils } from '@/libs/crud-pro/utils/MixinUtils';
13
- import { WorkbenchService } from '../WorkbenchService';
14
- import { validateByCfgString } from '@/libs/crud-pro/utils/ValidateUtils';
15
- import { API_BASE_TYPE, ApiBaseService } from '../base/ApiBaseService';
16
- import { GLOBAL_STATIC_CONFIG } from '@/libs/global-config/global-config';
17
-
18
- const lruCache = new LRUCache<string, any>({
19
- max: 500,
20
- ttl: 1000 * 60,
21
- ttlAutopurge: true,
22
- });
23
-
24
- @Provide()
25
- export class AnyApiService extends ApiBaseService {
26
- @Inject()
27
- protected ctx: Context;
28
-
29
- @Inject()
30
- private curdMixService: CurdMixService;
31
-
32
- @Inject()
33
- private anyApiSandboxService: AnyApiSandboxService;
34
-
35
- @Inject()
36
- protected workbenchService: WorkbenchService;
37
-
38
- async executeAnyApiMethod(methodCode: string, headers: any, body: any, query: any) {
39
- const anyApi = await this.getAnyApiMethod(methodCode);
40
- if (!anyApi || anyApi.status !== 1) {
41
- throw new BizException('接口不存在或已下线:' + methodCode);
42
- }
43
-
44
- const isSupport = await this.workbenchService.isSupportCurrentWorkbench(anyApi.workbench_code_array);
45
- if (!isSupport) {
46
- throw new BizException('此接口不支持在当前站点打开:' + methodCode);
47
- }
48
-
49
- await super.beforeCheckApiAccessibility(API_BASE_TYPE.PROXY_API, anyApi);
50
-
51
- if (!anyApi.func_code) {
52
- throw new BizException('没有配置代码:' + methodCode);
53
- }
54
-
55
- if (!this.checkFuncCode(anyApi.func_code)) {
56
- throw new BizException('接口代码校验失败:不满足形式: class HttpController { async handleRequest(params){} }; ');
57
- }
58
-
59
- const allParams: IRunInSandboxParams = { headers, body, query };
60
- allParams.params = this.toAnyApiParams(anyApi, allParams); // 组合参数
61
-
62
- // 执行代码
63
- const funcRes = await this.executeFunctionCode(anyApi, allParams);
64
- return funcRes;
65
- }
66
-
67
- private async getAnyApiMethod(methodCode: string): Promise<ISysAnyApiEntity> {
68
-
69
- // 开发环境,不使用缓存
70
- if (this.isEnableDebug()) {
71
- return this._getAnyApiMethod(methodCode);
72
- }
73
-
74
- // 线上环境可以使用缓存
75
- let anyApi = lruCache.get(methodCode);
76
- if (!anyApi) {
77
- anyApi = await this._getAnyApiMethod(methodCode);
78
- lruCache.set(methodCode, anyApi);
79
- }
80
- return anyApi;
81
- }
82
-
83
- private async _getAnyApiMethod(methodCode: string): Promise<ISysAnyApiEntity> {
84
- const { SystemDbName, SystemDbType } = GLOBAL_STATIC_CONFIG.getConfig();
85
-
86
- const res = await this.curdMixService.executeCrudByCfg(
87
- { condition: { method: methodCode } },
88
- {
89
- sqlTable: SystemTables.sys_anyapi,
90
- method: `get_sys_anyapi_${methodCode}`,
91
- sqlSimpleName: KeysOfSimpleSQL.SIMPLE_QUERY_ONE,
92
- sqlDatabase: SystemDbName,
93
- sqlDbType: SystemDbType,
94
- updateCfg: {},
95
- }
96
- );
97
- const obj: ISysAnyApiEntity = res.getOneObj();
98
- if (!obj) {
99
- return null;
100
- }
101
- obj.parsedOthers = parseJsonObject(obj.others);
102
- return obj;
103
- }
104
-
105
- /**
106
- * 构造参数
107
- * @param anyApi
108
- * @param allParams
109
- * @private
110
- */
111
- private toAnyApiParams(anyApi: ISysAnyApiEntity, allParams: IRunInSandboxParams): any {
112
- if (!anyApi.req_params) {
113
- return {};
114
- }
115
-
116
- const configs = anyApi.parsedOthers?.req_params || [];
117
- const params = {};
118
- for (let i = 0; i < configs.length; i++) {
119
- const { name, fromType, fromKey, validate_required, validate_cfg_list, valueType, defaultValue } = configs[i];
120
- const value = _.get(allParams, [fromType, fromKey], defaultValue);
121
- if (validate_required && MixinUtils.isEmpty(value)) {
122
- throw new BizException(`参数校验失败:${name} 不能为空`);
123
- }
124
-
125
- // 参数校验
126
- if (Array.isArray(validate_cfg_list)) {
127
- for (let j = 0; j < validate_cfg_list.length; j++) {
128
- const validateCfg = validate_cfg_list[j];
129
- validateByCfgString(validateCfg, value, name);
130
- }
131
- }
132
-
133
- // 格式转换
134
- params[name] = MixinUtils.parseValueByType(value, valueType);
135
- }
136
- return params;
137
- }
138
-
139
- /**
140
- * 运行代码
141
- * @param anyApiEntity
142
- * @param allParams
143
- * @private
144
- */
145
- private async executeFunctionCode(anyApiEntity: ISysAnyApiEntity, allParams: IRunInSandboxParams): Promise<any> {
146
- return this.anyApiSandboxService.runInSandbox(anyApiEntity, allParams);
147
- }
148
-
149
- private checkFuncCode(func_code: string): boolean {
150
- if (!func_code) {
151
- return false;
152
- }
153
-
154
- const lineHasKey = (lineTrim: string, target: string): boolean => {
155
- const words = lineTrim.split(/[\s{}();]/);
156
- for (let i = 0; i < words.length; i++) {
157
- const word = words[i];
158
- if (word && word === target) {
159
- return true;
160
- }
161
- }
162
- return false;
163
- };
164
-
165
- let hasClass = false;
166
- let hasMethod = false;
167
- const lines = func_code.split('\n');
168
- for (let i = 0; i < lines.length; i++) {
169
- const line = lines[i];
170
- if (line) {
171
- const lineTrim = line.trim();
172
- if (lineTrim) {
173
- if (lineHasKey(lineTrim, 'class') && lineHasKey(lineTrim, 'HttpController')) {
174
- hasClass = true;
175
- }
176
- if (lineHasKey(lineTrim, 'async') && lineHasKey(lineTrim, 'handleRequest')) {
177
- hasMethod = true;
178
- }
179
- if (lineTrim.startsWith('handleRequest')) {
180
- hasMethod = true;
181
- }
182
- }
183
- }
184
- }
185
- return hasMethod && hasClass;
186
- }
187
- }
1
+ import { Inject, Provide } from '@midwayjs/core';
2
+ import { Context } from '@midwayjs/koa';
3
+ import { KeysOfSimpleSQL } from '@/libs/crud-pro/models/keys';
4
+ import { SystemTables } from '@/models/SystemTables';
5
+ import { LRUCache } from 'lru-cache';
6
+ import { BizException } from '@/models/devops';
7
+ import { CurdMixService } from '../curd/CurdMixService';
8
+ import { ISysAnyApiEntity } from '@/models/SystemEntities';
9
+ import { AnyApiSandboxService, IRunInSandboxParams } from './AnyApiSandboxService';
10
+ import { parseJsonObject } from '@/libs/utils/functions';
11
+ import * as _ from 'lodash';
12
+ import { MixinUtils } from '@/libs/crud-pro/utils/MixinUtils';
13
+ import { WorkbenchService } from '../WorkbenchService';
14
+ import { validateByCfgString } from '@/libs/crud-pro/utils/ValidateUtils';
15
+ import { API_BASE_TYPE, ApiBaseService } from '../base/ApiBaseService';
16
+ import { GLOBAL_STATIC_CONFIG } from '@/libs/global-config/global-config';
17
+
18
+ const lruCache = new LRUCache<string, any>({
19
+ max: 500,
20
+ ttl: 1000 * 60,
21
+ ttlAutopurge: true,
22
+ });
23
+
24
+ @Provide()
25
+ export class AnyApiService extends ApiBaseService {
26
+ @Inject()
27
+ protected ctx: Context;
28
+
29
+ @Inject()
30
+ private curdMixService: CurdMixService;
31
+
32
+ @Inject()
33
+ private anyApiSandboxService: AnyApiSandboxService;
34
+
35
+ @Inject()
36
+ protected workbenchService: WorkbenchService;
37
+
38
+ async executeAnyApiMethod(methodCode: string, headers: any, body: any, query: any) {
39
+ const anyApi = await this.getAnyApiMethod(methodCode);
40
+ if (!anyApi || anyApi.status !== 1) {
41
+ throw new BizException('接口不存在或已下线:' + methodCode);
42
+ }
43
+
44
+ const isSupport = await this.workbenchService.isSupportCurrentWorkbench(anyApi.workbench_code_array);
45
+ if (!isSupport) {
46
+ throw new BizException('此接口不支持在当前站点打开:' + methodCode);
47
+ }
48
+
49
+ await super.beforeCheckApiAccessibility(API_BASE_TYPE.PROXY_API, anyApi);
50
+
51
+ if (!anyApi.func_code) {
52
+ throw new BizException('没有配置代码:' + methodCode);
53
+ }
54
+
55
+ if (!this.checkFuncCode(anyApi.func_code)) {
56
+ throw new BizException('接口代码校验失败:不满足形式: class HttpController { async handleRequest(params){} }; ');
57
+ }
58
+
59
+ const allParams: IRunInSandboxParams = { headers, body, query };
60
+ allParams.params = this.toAnyApiParams(anyApi, allParams); // 组合参数
61
+
62
+ // 执行代码
63
+ const funcRes = await this.executeFunctionCode(anyApi, allParams);
64
+ return funcRes;
65
+ }
66
+
67
+ private async getAnyApiMethod(methodCode: string): Promise<ISysAnyApiEntity> {
68
+ // 开发环境,不使用缓存
69
+ if (this.isEnableDebug()) {
70
+ return this._getAnyApiMethod(methodCode);
71
+ }
72
+
73
+ // 线上环境可以使用缓存
74
+ let anyApi = lruCache.get(methodCode);
75
+ if (!anyApi) {
76
+ anyApi = await this._getAnyApiMethod(methodCode);
77
+ lruCache.set(methodCode, anyApi);
78
+ }
79
+ return anyApi;
80
+ }
81
+
82
+ private async _getAnyApiMethod(methodCode: string): Promise<ISysAnyApiEntity> {
83
+ const { SystemDbName, SystemDbType } = GLOBAL_STATIC_CONFIG.getConfig();
84
+
85
+ const res = await this.curdMixService.executeCrudByCfg(
86
+ { condition: { method: methodCode } },
87
+ {
88
+ sqlTable: SystemTables.sys_anyapi,
89
+ method: `get_sys_anyapi_${methodCode}`,
90
+ sqlSimpleName: KeysOfSimpleSQL.SIMPLE_QUERY_ONE,
91
+ sqlDatabase: SystemDbName,
92
+ sqlDbType: SystemDbType,
93
+ updateCfg: {},
94
+ }
95
+ );
96
+ const obj: ISysAnyApiEntity = res.getOneObj();
97
+ if (!obj) {
98
+ return null;
99
+ }
100
+ obj.parsedOthers = parseJsonObject(obj.others);
101
+ return obj;
102
+ }
103
+
104
+ /**
105
+ * 构造参数
106
+ * @param anyApi
107
+ * @param allParams
108
+ * @private
109
+ */
110
+ private toAnyApiParams(anyApi: ISysAnyApiEntity, allParams: IRunInSandboxParams): any {
111
+ if (!anyApi.req_params) {
112
+ return {};
113
+ }
114
+
115
+ const configs = anyApi.parsedOthers?.req_params || [];
116
+ const params = {};
117
+ for (let i = 0; i < configs.length; i++) {
118
+ const { name, fromType, fromKey, validate_required, validate_cfg_list, valueType, defaultValue } = configs[i];
119
+ const value = _.get(allParams, [fromType, fromKey], defaultValue);
120
+ if (validate_required && MixinUtils.isEmpty(value)) {
121
+ throw new BizException(`参数校验失败:${name} 不能为空`);
122
+ }
123
+
124
+ // 参数校验
125
+ if (Array.isArray(validate_cfg_list)) {
126
+ for (let j = 0; j < validate_cfg_list.length; j++) {
127
+ const validateCfg = validate_cfg_list[j];
128
+ validateByCfgString(validateCfg, value, name);
129
+ }
130
+ }
131
+
132
+ // 格式转换
133
+ params[name] = MixinUtils.parseValueByType(value, valueType);
134
+ }
135
+ return params;
136
+ }
137
+
138
+ /**
139
+ * 运行代码
140
+ * @param anyApiEntity
141
+ * @param allParams
142
+ * @private
143
+ */
144
+ private async executeFunctionCode(anyApiEntity: ISysAnyApiEntity, allParams: IRunInSandboxParams): Promise<any> {
145
+ return this.anyApiSandboxService.runInSandbox(anyApiEntity, allParams);
146
+ }
147
+
148
+ private checkFuncCode(func_code: string): boolean {
149
+ if (!func_code) {
150
+ return false;
151
+ }
152
+
153
+ const lineHasKey = (lineTrim: string, target: string): boolean => {
154
+ const words = lineTrim.split(/[\s{}();]/);
155
+ for (let i = 0; i < words.length; i++) {
156
+ const word = words[i];
157
+ if (word && word === target) {
158
+ return true;
159
+ }
160
+ }
161
+ return false;
162
+ };
163
+
164
+ let hasClass = false;
165
+ let hasMethod = false;
166
+ const lines = func_code.split('\n');
167
+ for (let i = 0; i < lines.length; i++) {
168
+ const line = lines[i];
169
+ if (line) {
170
+ const lineTrim = line.trim();
171
+ if (lineTrim) {
172
+ if (lineHasKey(lineTrim, 'class') && lineHasKey(lineTrim, 'HttpController')) {
173
+ hasClass = true;
174
+ }
175
+ if (lineHasKey(lineTrim, 'async') && lineHasKey(lineTrim, 'handleRequest')) {
176
+ hasMethod = true;
177
+ }
178
+ if (lineTrim.startsWith('handleRequest')) {
179
+ hasMethod = true;
180
+ }
181
+ }
182
+ }
183
+ }
184
+ return hasMethod && hasClass;
185
+ }
186
+ }
@@ -59,7 +59,7 @@ class AsyncTaskRunner {
59
59
  completed_at: getCurrentFullMoment(),
60
60
  });
61
61
  } catch (error) {
62
- ANONYMOUS_CONTEXT.getApp().getCoreLogger().error('executeTaskList error', error);
62
+ ANONYMOUS_CONTEXT.getApp().getCoreLogger().error('[AsyncTaskRunner] executeTaskList error', error);
63
63
  }
64
64
  }
65
65
 
@@ -205,7 +205,7 @@ export class AsyncTaskRunnerService extends BaseService implements IScheduleServ
205
205
 
206
206
  // 开始执行。
207
207
  ASYNC_TASK_RUNNER.executeTaskList(taskList).then(() => {
208
- console.log('ASYNC_TASK_RUNNER finished taskIds ==> ' + JSON.stringify(taskIds));
208
+ console.log('[AsyncTaskRunnerService] ASYNC_TASK_RUNNER finished taskIds ==> ' + JSON.stringify(taskIds));
209
209
  });
210
210
  }
211
211
 
@@ -231,7 +231,7 @@ export class AsyncTaskRunnerService extends BaseService implements IScheduleServ
231
231
  try {
232
232
  await this.fetchPendingTasks();
233
233
  } catch (e) {
234
- console.error('fetchPendingTasks error', errorToString(e));
234
+ console.error('[AsyncTaskRunnerService] fetchPendingTasks error', errorToString(e));
235
235
  }
236
236
 
237
237
  await this.redisService.del(ASYNC_TASK_LOCK);