@tachybase/module-worker-thread 0.23.22 → 0.23.40

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 +1 @@
1
- (function(t,e){typeof exports=="object"&&typeof module!="undefined"?e(exports,require("@tachybase/client"),require("react/jsx-runtime"),require("@tachybase/schema"),require("antd")):typeof define=="function"&&define.amd?define(["exports","@tachybase/client","react/jsx-runtime","@tachybase/schema","antd"],e):(t=typeof globalThis!="undefined"?globalThis:t||self,e(t["@tachybase/module-worker-thread"]={},t["@tachybase/client"],t.jsxRuntime,t["@tachybase/schema"],t.antd))})(this,function(t,e,r,m,a){"use strict";var v=Object.defineProperty;var f=Object.getOwnPropertySymbols;var w=Object.prototype.hasOwnProperty,F=Object.prototype.propertyIsEnumerable;var x=(t,e,r)=>e in t?v(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,b=(t,e)=>{for(var r in e||(e={}))w.call(e,r)&&x(t,r,e[r]);if(f)for(var r of f(e))F.call(e,r)&&x(t,r,e[r]);return t};var c=(t,e,r)=>new Promise((m,a)=>{var u=n=>{try{o(r.next(n))}catch(p){a(p)}},l=n=>{try{o(r.throw(n))}catch(p){a(p)}},o=n=>n.done?m(n.value):Promise.resolve(n.value).then(u,l);o((r=r.apply(t,e)).next())});const u="worker-thread";function l(){return{t:(d,i={})=>e.i18n.t(d,b({ns:u},i))}}const o=s=>`{{t("${s}", { ns: ["${u}", "client"] })}}`,n=()=>{const s=e.useAPIClient();return{run(){return c(this,null,function*(){var i;(i=s.service("workerForm"))==null||i.refresh()})}}},p=s=>e.useRequest({url:"worker_thread:info"},s).data,k=()=>{const{setVisible:s}=e.useActionContext(),d=m.useForm(),{message:i}=a.App.useApp(),A=e.useAPIClient(),{t:I}=l();return{run(){return c(this,null,function*(){yield d.submit(),yield A.request({url:"worker_thread:preset",method:"post",data:{count:d.values.preset}}),i.success(I("Saved successfully")),s(!1)})}}},C={type:"object",properties:{workerForm:{"x-decorator":"Form","x-uid":"workerForm","x-decorator-props":{useValues:"{{ useWorkerInfo }}"},"x-component":"div",type:"void",title:'{{t("Worker thread info")}}',properties:{preset:{type:"number",title:o("Preset count"),minimum:0,"x-decorator":"FormItem","x-component":"InputNumber","x-component-props":{precision:0},required:!0},current:{type:"digit",title:o("Current count"),"x-decorator":"FormItem","x-component":"InputNumber","x-disabled":!0},busy:{type:"digit",title:o("Busy count"),"x-decorator":"FormItem","x-component":"InputNumber","x-disabled":!0},env:{type:"digit",title:o("Environment count"),"x-decorator":"FormItem","x-component":"InputNumber","x-disabled":!0},footer1:{type:"void","x-component":"ActionBar","x-component-props":{layout:"one-column"},properties:{submit:{title:o("Submit"),"x-component":"Action","x-component-props":{type:"primary",htmlType:"submit",useAction:"{{ resetWorkerCount }}"}},refresh:{title:o("Refresh"),"x-component":"Action","x-component-props":{type:"default",useAction:"{{ useRefresh }}"}}}}}}}},h=()=>r.jsx(a.Card,{bordered:!1,children:r.jsx(e.SchemaComponent,{scope:{resetWorkerCount:k,useWorkerInfo:p,useRefresh:n},schema:C})});class y extends e.Plugin{afterAdd(){return c(this,null,function*(){})}beforeLoad(){return c(this,null,function*(){})}load(){return c(this,null,function*(){this.app.addComponents({WorkerInfoPane:h}),this.app.systemSettingsManager.add("system-services."+u,{title:this.t("Worker thread"),icon:"ControlOutlined",Component:h,aclSnippet:`pm.system-services.${u}`,sort:10})})}}t.ModuleWorkerThreadClient=y,t.default=y,Object.defineProperties(t,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
1
+ (function(t,e){typeof exports=="object"&&typeof module!="undefined"?e(exports,require("@tachybase/client"),require("react/jsx-runtime"),require("@tachybase/schema"),require("antd")):typeof define=="function"&&define.amd?define(["exports","@tachybase/client","react/jsx-runtime","@tachybase/schema","antd"],e):(t=typeof globalThis!="undefined"?globalThis:t||self,e(t["@tachybase/module-worker-thread"]={},t["@tachybase/client"],t.jsxRuntime,t["@tachybase/schema"],t.antd))})(this,function(t,e,r,h,u){"use strict";var T=Object.defineProperty;var x=Object.getOwnPropertySymbols;var F=Object.prototype.hasOwnProperty,S=Object.prototype.propertyIsEnumerable;var b=(t,e,r)=>e in t?T(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,A=(t,e)=>{for(var r in e||(e={}))F.call(e,r)&&b(t,r,e[r]);if(x)for(var r of x(e))S.call(e,r)&&b(t,r,e[r]);return t};var c=(t,e,r)=>new Promise((h,u)=>{var p=n=>{try{o(r.next(n))}catch(l){u(l)}},d=n=>{try{o(r.throw(n))}catch(l){u(l)}},o=n=>n.done?h(n.value):Promise.resolve(n.value).then(p,d);o((r=r.apply(t,e)).next())});const p="worker-thread";function d(){return{t:(i,a={})=>e.i18n.t(i,A({ns:p},a))}}const o=s=>`{{t("${s}", { ns: ["${p}", "client"] })}}`,n=()=>{const s=e.useAPIClient();return{run(){return c(this,null,function*(){var a;(a=s.service("workerForm"))==null||a.refresh()})}}},l=s=>e.useRequest({url:"worker_thread:info"},s).data,k=()=>{const{setVisible:s}=e.useActionContext(),i=h.useForm(),{message:a}=u.App.useApp(),m=e.useAPIClient(),{t:C}=d();return{run(){return c(this,null,function*(){yield i.submit(),yield m.request({url:"worker_thread:preset",method:"post",data:{count:i.values.preset}}),a.success(C("Saved successfully")),s(!1)})}}},w=()=>{const{setVisible:s}=e.useActionContext(),{message:i}=u.App.useApp(),a=e.useAPIClient(),{t:m}=d();return{run(){return c(this,null,function*(){const I=i.loading(m("Restarting all..."),0);try{yield a.request({url:"worker_thread:restartAllForcely",method:"post",data:{}}),i.success(m("Restart all successfully"))}catch(g){i.error(g.message)}finally{I()}s(!1)})}}},v={type:"object",properties:{workerForm:{"x-decorator":"Form","x-uid":"workerForm","x-decorator-props":{useValues:"{{ useWorkerInfo }}"},"x-component":"div",type:"void",title:'{{t("Worker thread info")}}',properties:{preset:{type:"number",title:o("Preset count"),minimum:0,"x-decorator":"FormItem","x-component":"InputNumber","x-component-props":{precision:0},required:!0},current:{type:"digit",title:o("Current count"),"x-decorator":"FormItem","x-component":"InputNumber","x-disabled":!0},busy:{type:"digit",title:o("Busy count"),"x-decorator":"FormItem","x-component":"InputNumber","x-disabled":!0},env:{type:"digit",title:o("Environment count"),"x-decorator":"FormItem","x-component":"InputNumber","x-disabled":!0},footer1:{type:"void","x-component":"ActionBar","x-component-props":{layout:"one-column"},properties:{submit:{title:o("Submit"),"x-component":"Action","x-component-props":{type:"primary",htmlType:"submit",useAction:"{{ resetWorkerCount }}"}},refresh:{title:o("Refresh"),"x-component":"Action","x-component-props":{type:"default",useAction:"{{ useRefresh }}"}},restartAllForcely:{title:o("Restart all forcely"),"x-component":"Action","x-component-props":{type:"default",useAction:w,confirm:{title:o("Restart all forcely"),content:o("Are you sure you want to restart all worker threads? All worker threads that are currently processing main thread tasks will be immediately terminated")}}}}},helpText1:{type:"void","x-component":"div","x-component-props":{style:{color:"grey",fontSize:"12px",marginTop:"10px"}},"x-content":o("If the current preset count is less than the number of worker threads, it will wait for the worker threads to be idle before exiting")},helpText2:{type:"void","x-component":"div","x-component-props":{style:{color:"red",fontSize:"12px",marginTop:"10px"}},"x-content":o("The modification will not be refreshed immediately, please wait patiently for about 10 seconds, or click the refresh button to view the latest data")}}}}},y=()=>r.jsx(u.Card,{bordered:!1,children:r.jsx(e.SchemaComponent,{scope:{resetWorkerCount:k,useWorkerInfo:l,useRefresh:n},schema:v})});class f extends e.Plugin{afterAdd(){return c(this,null,function*(){})}beforeLoad(){return c(this,null,function*(){})}load(){return c(this,null,function*(){this.app.addComponents({WorkerInfoPane:y}),this.app.systemSettingsManager.add("system-services."+p,{title:this.t("Worker thread"),icon:"ControlOutlined",Component:y,aclSnippet:`pm.system-services.${p}`,sort:10})})}}t.ModuleWorkerThreadClient=f,t.default=f,Object.defineProperties(t,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
@@ -1,12 +1,12 @@
1
1
  module.exports = {
2
2
  "react": "18.3.1",
3
- "@tachybase/client": "0.23.22",
4
- "@tachybase/schema": "0.23.22",
3
+ "@tachybase/client": "0.23.40",
4
+ "@tachybase/schema": "0.23.40",
5
5
  "antd": "5.22.5",
6
- "@tachybase/server": "0.23.22",
7
- "@tachybase/logger": "0.23.22",
8
- "@tachybase/module-collection": "0.23.22",
9
- "@tachybase/module-user": "0.23.22",
10
- "@tachybase/utils": "0.23.22",
11
- "@tachybase/actions": "0.23.22"
6
+ "@tachybase/server": "0.23.40",
7
+ "@tachybase/logger": "0.23.40",
8
+ "@tachybase/module-collection": "0.23.40",
9
+ "@tachybase/module-user": "0.23.40",
10
+ "@tachybase/utils": "0.23.40",
11
+ "@tachybase/actions": "0.23.40"
12
12
  };
@@ -1,10 +1,14 @@
1
1
  {
2
+ "Are you sure you want to restart all worker threads? All worker threads that are currently processing main thread tasks will be immediately terminated": "Are you sure you want to restart all worker threads? All worker threads that are currently processing main thread tasks will be immediately terminated",
2
3
  "Busy count": "Busy count",
3
4
  "Current count": "Current count",
4
5
  "Environment count": "Environment count",
6
+ "If the current preset count is less than the number of worker threads, it will wait for the worker threads to be idle before exiting": "If the current preset count is less than the number of worker threads, it will wait for the worker threads to be idle before exiting",
5
7
  "Invalid worker count": "Invalid worker count",
6
8
  "No worker thread": "No worker thread",
7
9
  "Preset count": "Preset count",
10
+ "Restart all forcely": "Restart all forcely",
11
+ "The modification will not be refreshed immediately, please wait patiently for about 10 seconds, or click the refresh button to view the latest data": "The modification will not be refreshed immediately, please wait patiently for about 10 seconds, or click the refresh button to view the latest data",
8
12
  "The system is currently processing other tasks. Please try again later": "The system is currently processing other tasks. Please try again later",
9
13
  "Too many workers": "Too many workers",
10
14
  "Worker thread": "Worker thread",
@@ -1,10 +1,14 @@
1
1
  {
2
+ "Are you sure you want to restart all worker threads? All worker threads that are currently processing main thread tasks will be immediately terminated": "你确定要重启所有工作线程吗?会立即终止正在处理主线程任务的所有工作线程",
2
3
  "Busy count": "繁忙数量",
3
4
  "Current count": "当前数量",
4
5
  "Environment count": "环境变量预设数量",
6
+ "If the current preset count is less than the number of worker threads, it will wait for the worker threads to be idle before exiting": "提交修改如果当前预设数量小于工作线程数量,则会等待工作线程空闲后再退出",
5
7
  "Invalid worker count": "无效的线程数",
6
8
  "No worker thread": "当前没有工作线程",
7
9
  "Preset count": "预设数量",
10
+ "Restart all forcely": "强制重启所有",
11
+ "The modification will not be refreshed immediately, please wait patiently for about 10 seconds, or click the refresh button to view the latest data": "修改后不会立即刷新,耐心等待10秒左右,也可以点击刷新按钮查看最新数据",
8
12
  "The system is currently processing other tasks. Please try again later": "当前系统处理其他事务,请稍后重试",
9
13
  "Too many workers": "设置工作线程过多",
10
14
  "Worker thread": "工作线程",
@@ -40,14 +40,24 @@ var import_workerTypes = require("./workerTypes");
40
40
  const loggerOptions = {
41
41
  system: {
42
42
  transports: (0, import_logger.getLoggerTransport)(),
43
- level: (0, import_logger.getLoggerLevel)()
44
- // TODO: 后续考虑是否提到info
43
+ level: process.env.LOGGER_LEVEL || "info"
45
44
  },
46
45
  request: {
47
46
  transports: (0, import_logger.getLoggerTransport)(),
48
- level: (0, import_logger.getLoggerLevel)()
47
+ level: process.env.LOGGER_LEVEL || "info"
49
48
  }
50
49
  };
50
+ async function reloadCustomCollections(app) {
51
+ const customCollections = await app.db.getRepository("collections").load();
52
+ for (const [key, collection] of app.db.collections) {
53
+ const dumpRules = collection.options.dumpRules;
54
+ if ((dumpRules == null ? void 0 : dumpRules.group) === "custom") {
55
+ if (!customCollections.includes(collection.name)) {
56
+ app.db.collections.delete(collection.name);
57
+ }
58
+ }
59
+ }
60
+ }
51
61
  const handleWorkerMessages = (app) => {
52
62
  if (import_worker_threads.isMainThread) {
53
63
  return;
@@ -56,14 +66,22 @@ const handleWorkerMessages = (app) => {
56
66
  event: import_workerTypes.WorkerEvent.Started
57
67
  });
58
68
  import_worker_threads.parentPort.on("message", async (message) => {
59
- app.logger.info("[worker] input", message);
69
+ var _a;
70
+ if ((_a = message.values) == null ? void 0 : _a.inputLog) {
71
+ app.logger.info("[worker] input", message.values.inputLog);
72
+ } else {
73
+ app.logger.info("[worker] input", message);
74
+ }
60
75
  const { reqId, event } = message;
61
76
  if (event === import_workerTypes.WorkerEvent.PluginMethod) {
62
77
  try {
63
- const { plugin, method, params } = message.values;
78
+ const { plugin, method, params, reloadCols = true } = message.values;
64
79
  const appPlugin = app.pm.get(plugin);
80
+ if (reloadCols) {
81
+ await reloadCustomCollections(app);
82
+ }
65
83
  const result = await appPlugin[method](params);
66
- app.logger.info(`[worker] output ${result}`);
84
+ app.logger.info(`[worker] output for ${plugin}.${method}:`, result);
67
85
  import_worker_threads.parentPort.postMessage({
68
86
  event,
69
87
  reqId,
@@ -23,6 +23,8 @@ export declare class WorkerManager {
23
23
  private addWorker;
24
24
  clear(): Promise<void>;
25
25
  resetWorkerNum(targetNum: number): Promise<void>;
26
+ /** 强制重启所有线程 */
27
+ restartAllForcely(): Promise<void>;
26
28
  /**
27
29
  * 检查并更新并发计数
28
30
  * @param key - 用于缓存的键
@@ -40,7 +42,7 @@ export declare class WorkerManager {
40
42
  /**
41
43
  * 运行插件方法
42
44
  */
43
- callPluginMethod(values: WorkerEventInputPluginMethod): Promise<unknown>;
45
+ callPluginMethod(values: WorkerEventInputPluginMethod): Promise<any>;
44
46
  private handleWorkerCompletion;
45
47
  /**
46
48
  * 运行通用方法
@@ -125,6 +125,7 @@ class WorkerManager {
125
125
  });
126
126
  worker.on("exit", async (code) => {
127
127
  if (code === 0 || code === 1) {
128
+ this.app.logger.debug(`[worker] terminated with code ${code}`);
128
129
  return;
129
130
  }
130
131
  this.errorRecoveryTimes++;
@@ -178,6 +179,16 @@ class WorkerManager {
178
179
  }
179
180
  }
180
181
  }
182
+ /** 强制重启所有线程 */
183
+ async restartAllForcely() {
184
+ if (!import_worker_threads.isMainThread) {
185
+ return;
186
+ }
187
+ const workerNum = this.workerNum;
188
+ await this.clear();
189
+ this.workerNum = workerNum;
190
+ await this.initWorkers();
191
+ }
181
192
  /**
182
193
  * 检查并更新并发计数
183
194
  * @param key - 用于缓存的键
@@ -245,15 +256,25 @@ class WorkerManager {
245
256
  throw new Error("The system is currently processing other tasks. Please try again later");
246
257
  }
247
258
  }
248
- const result = await this.callMethod(import_workerTypes.WorkerEvent.PluginMethod, {
249
- ...values,
250
- plugin: this.app.pm.get(values.plugin).name
251
- });
252
- if (values.globalConcurrency) {
253
- this.decrementConcurrencyCount(this.getGlobalKey(), this.cache);
259
+ let result;
260
+ let error;
261
+ try {
262
+ result = await this.callMethod(import_workerTypes.WorkerEvent.PluginMethod, {
263
+ ...values,
264
+ plugin: this.app.pm.get(values.plugin).name
265
+ });
266
+ } catch (err) {
267
+ error = err;
268
+ } finally {
269
+ if (values.globalConcurrency) {
270
+ this.decrementConcurrencyCount(this.getGlobalKey(), this.cache);
271
+ }
272
+ if (values.concurrency) {
273
+ this.decrementConcurrencyCount(this.getPluginMethodKey(values), this.cache);
274
+ }
254
275
  }
255
- if (values.concurrency) {
256
- this.decrementConcurrencyCount(this.getPluginMethodKey(values), this.cache);
276
+ if (error) {
277
+ throw error;
257
278
  }
258
279
  return result;
259
280
  }
@@ -298,11 +319,13 @@ class WorkerManager {
298
319
  let timeout;
299
320
  let handleMessage;
300
321
  let handleError;
322
+ let handleExit;
301
323
  handleMessage = (message) => {
302
324
  if (message.reqId === reqId) {
303
325
  clearTimeout(timeout);
304
326
  worker.off("message", handleMessage);
305
327
  worker.off("error", handleError);
328
+ worker.off("exit", handleExit);
306
329
  this.handleWorkerCompletion(worker, reqId, resolve, message.result);
307
330
  }
308
331
  };
@@ -310,6 +333,15 @@ class WorkerManager {
310
333
  clearTimeout(timeout);
311
334
  worker.off("message", handleMessage);
312
335
  worker.off("error", handleError);
336
+ worker.off("exit", handleExit);
337
+ this.handleWorkerCompletion(worker, reqId, resolve, void 0, reject, error);
338
+ };
339
+ handleExit = (code) => {
340
+ clearTimeout(timeout);
341
+ worker.off("message", handleMessage);
342
+ worker.off("error", handleError);
343
+ worker.off("exit", handleExit);
344
+ const error = new Error(`Worker stopped with exit code ${code}`);
313
345
  this.handleWorkerCompletion(worker, reqId, resolve, void 0, reject, error);
314
346
  };
315
347
  timeout = setTimeout(
@@ -329,6 +361,7 @@ class WorkerManager {
329
361
  );
330
362
  worker.on("message", handleMessage);
331
363
  worker.on("error", handleError);
364
+ worker.on("exit", handleExit);
332
365
  worker.postMessage({
333
366
  reqId,
334
367
  event: workerEvent,
@@ -12,6 +12,8 @@ export type WorkerEventInputPluginMethod<T = any> = WorkerEventInputDefault & {
12
12
  plugin: Constructor<Plugin> | string;
13
13
  method: string;
14
14
  params: T;
15
+ reloadCols?: boolean;
16
+ inputLog?: object | string;
15
17
  };
16
18
  export type WorkerEventInput = WorkerEventInputPluginMethod;
17
19
  export type WorkerWebInfo = {
@@ -2,4 +2,5 @@ import { Context, Next } from '@tachybase/actions';
2
2
  export declare class WorkerWebController {
3
3
  info(ctx: Context, next: Next): Promise<void>;
4
4
  preset(ctx: Context, next: Next): Promise<void>;
5
+ resetAllForcely(ctx: Context, next: Next): Promise<void>;
5
6
  }
@@ -68,8 +68,8 @@ module.exports = __toCommonJS(workerWebController_exports);
68
68
  var import_utils = require("@tachybase/utils");
69
69
  var import_constants = require("../constants");
70
70
  var import_constants2 = require("./constants");
71
- var _preset_dec, _info_dec, _WorkerWebController_decorators, _init;
72
- _WorkerWebController_decorators = [(0, import_utils.Controller)("worker_thread")], _info_dec = [(0, import_utils.Action)("info", { acl: "blocked" })], _preset_dec = [(0, import_utils.Action)("preset", { acl: "blocked" })];
71
+ var _resetAllForcely_dec, _preset_dec, _info_dec, _WorkerWebController_decorators, _init;
72
+ _WorkerWebController_decorators = [(0, import_utils.Controller)("worker_thread")], _info_dec = [(0, import_utils.Action)("info", { acl: "blocked" })], _preset_dec = [(0, import_utils.Action)("preset", { acl: "blocked" })], _resetAllForcely_dec = [(0, import_utils.Action)("restartAllForcely", { acl: "blocked" })];
73
73
  class WorkerWebController {
74
74
  constructor() {
75
75
  __runInitializers(_init, 5, this);
@@ -112,10 +112,18 @@ class WorkerWebController {
112
112
  success: true
113
113
  };
114
114
  }
115
+ async resetAllForcely(ctx, next) {
116
+ const app = ctx.app;
117
+ await app.worker.restartAllForcely();
118
+ ctx.body = {
119
+ success: true
120
+ };
121
+ }
115
122
  }
116
123
  _init = __decoratorStart(null);
117
124
  __decorateElement(_init, 1, "info", _info_dec, WorkerWebController);
118
125
  __decorateElement(_init, 1, "preset", _preset_dec, WorkerWebController);
126
+ __decorateElement(_init, 1, "resetAllForcely", _resetAllForcely_dec, WorkerWebController);
119
127
  WorkerWebController = __decorateElement(_init, 0, "WorkerWebController", _WorkerWebController_decorators, WorkerWebController);
120
128
  __runInitializers(_init, 1, WorkerWebController);
121
129
  // Annotate the CommonJS export names for ESM import in node:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tachybase/module-worker-thread",
3
- "version": "0.23.22",
3
+ "version": "0.23.40",
4
4
  "description": "Worker thread for executing time-consuming tasks",
5
5
  "main": "dist/server/index.js",
6
6
  "dependencies": {},
@@ -9,15 +9,15 @@
9
9
  "tsx": "^4.19.2"
10
10
  },
11
11
  "peerDependencies": {
12
- "@tachybase/actions": "0.23.22",
13
- "@tachybase/client": "0.23.22",
14
- "@tachybase/logger": "0.23.22",
15
- "@tachybase/module-user": "0.23.22",
16
- "@tachybase/module-collection": "0.23.22",
17
- "@tachybase/server": "0.23.22",
18
- "@tachybase/schema": "0.23.22",
19
- "@tachybase/test": "0.23.22",
20
- "@tachybase/utils": "0.23.22"
12
+ "@tachybase/client": "0.23.40",
13
+ "@tachybase/actions": "0.23.40",
14
+ "@tachybase/logger": "0.23.40",
15
+ "@tachybase/module-collection": "0.23.40",
16
+ "@tachybase/module-user": "0.23.40",
17
+ "@tachybase/server": "0.23.40",
18
+ "@tachybase/schema": "0.23.40",
19
+ "@tachybase/test": "0.23.40",
20
+ "@tachybase/utils": "0.23.40"
21
21
  },
22
22
  "description.zh-CN": "工作线程,用于执行耗时任务",
23
23
  "displayName.zh-CN": "工作线程",