@hile/message-worker-thread 1.0.0
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.
- package/README.md +130 -0
- package/SKILL.md +160 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +59 -0
- package/package.json +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# @hile/message-worker-thread
|
|
2
|
+
|
|
3
|
+
基于 `@hile/message-modem` 的 Node.js Worker Threads 通信抽象实现。让主线程与 Worker 线程之间的请求/响应通信像调用函数一样简单。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @hile/message-worker-thread
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 核心特性
|
|
12
|
+
|
|
13
|
+
- **双端支持** — 主线程传入 `Worker` 或 `MessagePort`,Worker 线程端零配置
|
|
14
|
+
- **继承模式** — 继承 `MessageWorkerThread` 并实现 `exec` 方法
|
|
15
|
+
- **请求/响应** — 继承 `MessageModem` 的全部能力
|
|
16
|
+
- **超时控制** — 默认 30 秒,可按请求自定义
|
|
17
|
+
- **主动中止** — `abort()` 取消等待并通知对端
|
|
18
|
+
- **错误传播** — `Exception` 带 status 透传,普通 Error 映射为 500
|
|
19
|
+
- **资源清理** — `dispose()` 移除监听,避免内存泄漏
|
|
20
|
+
|
|
21
|
+
## 快速开始
|
|
22
|
+
|
|
23
|
+
### 第一步:定义子类
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { MessageWorkerThread } from '@hile/message-worker-thread';
|
|
27
|
+
import { Exception } from '@hile/message-modem';
|
|
28
|
+
|
|
29
|
+
class ComputeWorker extends MessageWorkerThread {
|
|
30
|
+
protected async exec(data: any): Promise<any> {
|
|
31
|
+
switch (data?.action) {
|
|
32
|
+
case 'compute':
|
|
33
|
+
return data.value * 2;
|
|
34
|
+
case 'restricted':
|
|
35
|
+
throw new Exception(403, 'not allowed');
|
|
36
|
+
default:
|
|
37
|
+
return data;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 第二步:主线程
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { Worker } from 'node:worker_threads';
|
|
47
|
+
|
|
48
|
+
class MainThread extends MessageWorkerThread {
|
|
49
|
+
protected async exec(data: any): Promise<any> {
|
|
50
|
+
return { reply: 'from main', query: data };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const worker = new Worker('./worker.js');
|
|
55
|
+
const wt = new MainThread(worker);
|
|
56
|
+
|
|
57
|
+
const result = await wt.request({ action: 'compute', value: 42 }).response();
|
|
58
|
+
console.log(result); // 84
|
|
59
|
+
|
|
60
|
+
wt.dispose();
|
|
61
|
+
await worker.terminate();
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 第三步:Worker 线程(worker.js)
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
const wt = new ComputeWorker(); // 无参数 → 自动使用 parentPort
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## API
|
|
71
|
+
|
|
72
|
+
### `MessageWorkerThread`(抽象类)
|
|
73
|
+
|
|
74
|
+
| 方法 | 签名 | 说明 |
|
|
75
|
+
|------|------|------|
|
|
76
|
+
| `constructor` | `new SubClass(port?: Worker \| MessagePort)` | 主线程传 Worker/MessagePort;Worker 线程不传参数 |
|
|
77
|
+
| `exec` | `protected abstract exec(data: any): Promise<any>` | 子类实现:处理对端请求 |
|
|
78
|
+
| `request` | `request<T>(data: T, timeout?: number)` | 向对端发送请求,返回 `{ abort, response }` |
|
|
79
|
+
| `dispose` | `dispose(): void` | 移除消息监听,释放资源 |
|
|
80
|
+
|
|
81
|
+
### `request` 返回值
|
|
82
|
+
|
|
83
|
+
| 属性 | 类型 | 说明 |
|
|
84
|
+
|------|------|------|
|
|
85
|
+
| `abort` | `() => void` | 中止请求 |
|
|
86
|
+
| `response` | `<U>() => Promise<U>` | 等待对端响应 |
|
|
87
|
+
|
|
88
|
+
## 也可以用 MessageChannel
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
import { MessageChannel } from 'node:worker_threads';
|
|
92
|
+
|
|
93
|
+
const { port1, port2 } = new MessageChannel();
|
|
94
|
+
const side1 = new MySide(port1);
|
|
95
|
+
const side2 = new MySide(port2);
|
|
96
|
+
|
|
97
|
+
const result = await side1.request('hello').response();
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## 超时与中止
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { AbortException, Exception } from '@hile/message-modem';
|
|
104
|
+
|
|
105
|
+
// 5 秒超时
|
|
106
|
+
const result = await wt.request(data, 5000).response();
|
|
107
|
+
|
|
108
|
+
// 主动中止
|
|
109
|
+
const req = wt.request(data);
|
|
110
|
+
setTimeout(() => req.abort(), 3000);
|
|
111
|
+
try {
|
|
112
|
+
await req.response();
|
|
113
|
+
} catch (e) {
|
|
114
|
+
if (e instanceof AbortException) {
|
|
115
|
+
console.log('请求被中止或超时');
|
|
116
|
+
} else if (e instanceof Exception) {
|
|
117
|
+
console.log(`远端错误 [${e.status}]: ${e.message}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## 注意事项
|
|
123
|
+
|
|
124
|
+
- `MessageWorkerThread` 是 **抽象类**,不能直接实例化
|
|
125
|
+
- Worker 线程端不传参数时,必须在 Worker 线程内运行(`parentPort` 可用)
|
|
126
|
+
- 使用完毕后务必 `dispose()` + `worker.terminate()`
|
|
127
|
+
|
|
128
|
+
## License
|
|
129
|
+
|
|
130
|
+
MIT
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: message-worker-thread
|
|
3
|
+
description: Code generation and contribution rules for @hile/message-worker-thread. Use when editing this package or when the user asks about @hile/message-worker-thread patterns or API.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @hile/message-worker-thread
|
|
7
|
+
|
|
8
|
+
本文档是面向 AI 编码模型和人类开发者的 **代码生成规范**,阅读后应能正确地使用本库编写符合架构规则的代码。
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 1. 架构总览
|
|
13
|
+
|
|
14
|
+
`@hile/message-worker-thread` 是 `@hile/message-modem` 的 **Node.js Worker Threads 抽象实现**,用于主线程与 Worker 线程之间的请求/响应通信。
|
|
15
|
+
|
|
16
|
+
`MessageWorkerThread` 本身是 **抽象类**,实现了 `post`(通过 `postMessage` 发送),`exec` 方法留给子类实现。
|
|
17
|
+
|
|
18
|
+
继承链:
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
MessageModem (abstract) ← post + exec 均抽象
|
|
22
|
+
└── MessageWorkerThread (abstract) ← 实现 post,exec 仍抽象
|
|
23
|
+
└── 用户子类 ← 实现 exec
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
通道类型:
|
|
27
|
+
|
|
28
|
+
- 主线程端:传入 `Worker` 实例或 `MessagePort`
|
|
29
|
+
- Worker 线程端:不传参数,自动使用 `parentPort`
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 2. 类型签名
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { MessageModem, type MessageTransferFormat } from '@hile/message-modem';
|
|
37
|
+
import type { Worker, MessagePort } from 'node:worker_threads';
|
|
38
|
+
|
|
39
|
+
abstract class MessageWorkerThread extends MessageModem {
|
|
40
|
+
constructor(port?: Worker | MessagePort);
|
|
41
|
+
|
|
42
|
+
// 子类必须实现
|
|
43
|
+
protected abstract exec(data: any): Promise<any>;
|
|
44
|
+
|
|
45
|
+
// 向对端发送请求
|
|
46
|
+
public request<T = any>(data: T, timeout?: number): {
|
|
47
|
+
abort: () => void;
|
|
48
|
+
response: <U = any>() => Promise<U>;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// 移除消息监听
|
|
52
|
+
public dispose(): void;
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 3. 代码生成模板与规则
|
|
59
|
+
|
|
60
|
+
### 3.1 基本子类模板
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { MessageWorkerThread } from '@hile/message-worker-thread';
|
|
64
|
+
|
|
65
|
+
class MyWorkerThread extends MessageWorkerThread {
|
|
66
|
+
protected async exec(data: any): Promise<any> {
|
|
67
|
+
switch (data?.action) {
|
|
68
|
+
case 'ping':
|
|
69
|
+
return 'pong';
|
|
70
|
+
default:
|
|
71
|
+
return data;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 3.2 主线程端模板
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { Worker } from 'node:worker_threads';
|
|
81
|
+
|
|
82
|
+
class MainThread extends MessageWorkerThread {
|
|
83
|
+
protected async exec(data: any): Promise<any> {
|
|
84
|
+
return { reply: 'from main', query: data };
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const worker = new Worker('./worker.js');
|
|
89
|
+
const wt = new MainThread(worker);
|
|
90
|
+
|
|
91
|
+
const result = await wt.request({ action: 'compute', value: 42 }).response();
|
|
92
|
+
console.log(result);
|
|
93
|
+
|
|
94
|
+
wt.dispose();
|
|
95
|
+
await worker.terminate();
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 3.3 Worker 线程端模板
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
// worker.js
|
|
102
|
+
import { MessageWorkerThread } from '@hile/message-worker-thread';
|
|
103
|
+
import { Exception } from '@hile/message-modem';
|
|
104
|
+
|
|
105
|
+
class WorkerThread extends MessageWorkerThread {
|
|
106
|
+
protected async exec(data: any): Promise<any> {
|
|
107
|
+
if (data.action === 'compute') return data.value * 2;
|
|
108
|
+
if (data.action === 'restricted') throw new Exception(403, 'not allowed');
|
|
109
|
+
return data;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const wt = new WorkerThread(); // 无参数 → 使用 parentPort
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 3.4 MessageChannel 场景模板
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { MessageChannel } from 'node:worker_threads';
|
|
120
|
+
|
|
121
|
+
const { port1, port2 } = new MessageChannel();
|
|
122
|
+
const side1 = new MySide1(port1);
|
|
123
|
+
const side2 = new MySide2(port2);
|
|
124
|
+
|
|
125
|
+
// 双向通信
|
|
126
|
+
const res = await side1.request('hello').response();
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### 3.5 强制规则
|
|
130
|
+
|
|
131
|
+
| 规则 | 说明 |
|
|
132
|
+
|------|------|
|
|
133
|
+
| **必须继承并实现 `exec`** | `MessageWorkerThread` 是抽象类 |
|
|
134
|
+
| **主线程端必须传入 `Worker` 或 `MessagePort`** | `new Worker()` 返回值 |
|
|
135
|
+
| **Worker 线程端不传参数** | 自动使用 `parentPort` |
|
|
136
|
+
| **用完必须 `dispose()`** | 避免内存泄漏 |
|
|
137
|
+
| **主线程还需 `worker.terminate()`** | 关闭 Worker 线程 |
|
|
138
|
+
|
|
139
|
+
### 3.6 反模式
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
// ❌ 不能直接实例化
|
|
143
|
+
const wt = new MessageWorkerThread(worker); // abstract
|
|
144
|
+
|
|
145
|
+
// ✅ 继承并实现 exec
|
|
146
|
+
class MyWT extends MessageWorkerThread {
|
|
147
|
+
protected async exec(data: any) { return data; }
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ❌ Worker 线程里传入 Worker 实例没有意义
|
|
151
|
+
const wt = new MyWT(someWorker); // Worker 线程里没有子 Worker
|
|
152
|
+
|
|
153
|
+
// ✅ Worker 线程不传参数
|
|
154
|
+
const wt = new MyWT();
|
|
155
|
+
|
|
156
|
+
// ❌ 忘记 dispose 和 terminate
|
|
157
|
+
// ✅ 清理
|
|
158
|
+
wt.dispose();
|
|
159
|
+
await worker.terminate();
|
|
160
|
+
```
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { MessageModem, type MessageTransferFormat } from '@hile/message-modem';
|
|
2
|
+
import { type Worker, type MessagePort } from 'node:worker_threads';
|
|
3
|
+
/**
|
|
4
|
+
* 支持主线程和 Worker 线程双端使用的 worker_threads 通信层。
|
|
5
|
+
* exec 方法由子类实现,本类不做实现。
|
|
6
|
+
*
|
|
7
|
+
* - Worker 线程端:不传参数,自动绑定 parentPort
|
|
8
|
+
* - 主线程端:传入 new Worker() 返回的 Worker 实例(或 MessagePort)
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* class MyWorkerThread extends MessageWorkerThread {
|
|
12
|
+
* protected exec(data: any): Promise<any> {
|
|
13
|
+
* return Promise.resolve(data);
|
|
14
|
+
* }
|
|
15
|
+
* }
|
|
16
|
+
*
|
|
17
|
+
* // 主线程
|
|
18
|
+
* const worker = new Worker('./worker.js');
|
|
19
|
+
* const wt = new MyWorkerThread(worker);
|
|
20
|
+
* const res = await wt.request('hello').response();
|
|
21
|
+
* wt.dispose();
|
|
22
|
+
* await worker.terminate();
|
|
23
|
+
*
|
|
24
|
+
* // Worker 线程
|
|
25
|
+
* const wt = new MyWorkerThread();
|
|
26
|
+
*/
|
|
27
|
+
export declare abstract class MessageWorkerThread extends MessageModem {
|
|
28
|
+
private readonly port;
|
|
29
|
+
private readonly listener;
|
|
30
|
+
constructor(port?: Worker | MessagePort);
|
|
31
|
+
protected post<T = any>(data: MessageTransferFormat<T>): void;
|
|
32
|
+
/**
|
|
33
|
+
* 向对端发送请求
|
|
34
|
+
*/
|
|
35
|
+
request<T = any>(data: T, timeout?: number): {
|
|
36
|
+
abort: () => void;
|
|
37
|
+
response: <U = any>() => Promise<U>;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* 移除消息监听,释放资源
|
|
41
|
+
*/
|
|
42
|
+
dispose(): void;
|
|
43
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { MessageModem } from '@hile/message-modem';
|
|
2
|
+
import { parentPort } from 'node:worker_threads';
|
|
3
|
+
/**
|
|
4
|
+
* 支持主线程和 Worker 线程双端使用的 worker_threads 通信层。
|
|
5
|
+
* exec 方法由子类实现,本类不做实现。
|
|
6
|
+
*
|
|
7
|
+
* - Worker 线程端:不传参数,自动绑定 parentPort
|
|
8
|
+
* - 主线程端:传入 new Worker() 返回的 Worker 实例(或 MessagePort)
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* class MyWorkerThread extends MessageWorkerThread {
|
|
12
|
+
* protected exec(data: any): Promise<any> {
|
|
13
|
+
* return Promise.resolve(data);
|
|
14
|
+
* }
|
|
15
|
+
* }
|
|
16
|
+
*
|
|
17
|
+
* // 主线程
|
|
18
|
+
* const worker = new Worker('./worker.js');
|
|
19
|
+
* const wt = new MyWorkerThread(worker);
|
|
20
|
+
* const res = await wt.request('hello').response();
|
|
21
|
+
* wt.dispose();
|
|
22
|
+
* await worker.terminate();
|
|
23
|
+
*
|
|
24
|
+
* // Worker 线程
|
|
25
|
+
* const wt = new MyWorkerThread();
|
|
26
|
+
*/
|
|
27
|
+
export class MessageWorkerThread extends MessageModem {
|
|
28
|
+
port;
|
|
29
|
+
listener;
|
|
30
|
+
constructor(port) {
|
|
31
|
+
super();
|
|
32
|
+
if (port) {
|
|
33
|
+
this.port = port;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
if (!parentPort) {
|
|
37
|
+
throw new Error('parentPort is not available. Ensure this code runs inside a Worker thread.');
|
|
38
|
+
}
|
|
39
|
+
this.port = parentPort;
|
|
40
|
+
}
|
|
41
|
+
this.listener = (msg) => this.receive(msg);
|
|
42
|
+
this.port.on('message', this.listener);
|
|
43
|
+
}
|
|
44
|
+
post(data) {
|
|
45
|
+
this.port.postMessage(data);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 向对端发送请求
|
|
49
|
+
*/
|
|
50
|
+
request(data, timeout) {
|
|
51
|
+
return this.send(data, timeout);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 移除消息监听,释放资源
|
|
55
|
+
*/
|
|
56
|
+
dispose() {
|
|
57
|
+
this.port.removeListener('message', this.listener);
|
|
58
|
+
}
|
|
59
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hile/message-worker-thread",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc -b && fix-esm-import-path --preserve-import-type ./dist",
|
|
8
|
+
"dev": "tsc -b --watch",
|
|
9
|
+
"test": "vitest run"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"README.md",
|
|
14
|
+
"SKILL.md"
|
|
15
|
+
],
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"fix-esm-import-path": "^1.10.3",
|
|
22
|
+
"vitest": "^4.0.18"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@hile/message-modem": "^1.0.1"
|
|
26
|
+
},
|
|
27
|
+
"gitHead": "426933bf98ed09d0e52b6cb63792cd3b2cf3fee1"
|
|
28
|
+
}
|