@matterbridge/thread 3.6.1-dev-20260309-6341dee → 3.6.1-dev-20260310-7887380
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/dist/broadcastServer.js +1 -1
- package/dist/threadsManager.d.ts +3 -1
- package/dist/threadsManager.js +13 -9
- package/dist/workerCheckUpdates.js +1 -1
- package/dist/workerSpawnCommand.js +23 -6
- package/dist/workerWrapper.d.ts +7 -3
- package/dist/workerWrapper.js +49 -24
- package/package.json +3 -3
package/dist/broadcastServer.js
CHANGED
|
@@ -140,7 +140,7 @@ export class BroadcastServer extends EventEmitter {
|
|
|
140
140
|
if (message.timestamp === undefined) {
|
|
141
141
|
message.timestamp = Date.now();
|
|
142
142
|
}
|
|
143
|
-
if (message.dst === this.name
|
|
143
|
+
if (message.dst === this.name) {
|
|
144
144
|
message.dst = message.src;
|
|
145
145
|
}
|
|
146
146
|
message.src = this.name;
|
package/dist/threadsManager.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { Worker } from 'node:worker_threads';
|
|
2
|
+
import type { WorkerData } from '@matterbridge/types';
|
|
2
3
|
import { LogLevel } from 'node-ansi-logger';
|
|
3
4
|
export declare class ThreadsManager {
|
|
4
5
|
private debug;
|
|
5
6
|
private verbose;
|
|
7
|
+
private tracker;
|
|
6
8
|
private log;
|
|
7
9
|
static logLevel: LogLevel;
|
|
8
10
|
private server;
|
|
@@ -14,7 +16,7 @@ export declare class ThreadsManager {
|
|
|
14
16
|
destroy(): void;
|
|
15
17
|
private msgHandler;
|
|
16
18
|
private intervalHandler;
|
|
17
|
-
runThread(name: string, workerData?:
|
|
19
|
+
runThread(name: string, workerData?: WorkerData, argv?: string[], env?: NodeJS.ProcessEnv, execArgv?: string[], pipedOutput?: boolean): Worker;
|
|
18
20
|
resolvePath(fileName: string): string;
|
|
19
21
|
createESMWorker(name: string, relativePath: string, workerData?: Record<string, boolean | number | string | object>, argv?: string[], env?: NodeJS.ProcessEnv, execArgv?: string[], pipedOutput?: boolean): Worker;
|
|
20
22
|
}
|
package/dist/threadsManager.js
CHANGED
|
@@ -10,6 +10,7 @@ import { BroadcastServer } from './broadcastServer.js';
|
|
|
10
10
|
export class ThreadsManager {
|
|
11
11
|
debug;
|
|
12
12
|
verbose;
|
|
13
|
+
tracker;
|
|
13
14
|
log;
|
|
14
15
|
static logLevel;
|
|
15
16
|
server;
|
|
@@ -25,6 +26,7 @@ export class ThreadsManager {
|
|
|
25
26
|
constructor(intervalMs = 10_000) {
|
|
26
27
|
this.debug = hasParameter('debug') || hasParameter('verbose') || hasParameter('debug-threads') || hasParameter('verbose-threads');
|
|
27
28
|
this.verbose = hasParameter('verbose') || hasParameter('verbose-threads');
|
|
29
|
+
this.tracker = hasParameter('tracker') || hasParameter('tracker-threads');
|
|
28
30
|
this.log = new AnsiLogger({
|
|
29
31
|
logName: 'ThreadsManager',
|
|
30
32
|
logNameColor: MAGENTA,
|
|
@@ -97,17 +99,18 @@ export class ThreadsManager {
|
|
|
97
99
|
if (threadInfo.worker) {
|
|
98
100
|
throw new Error(`Thread ${name} is already running with thread ID ${threadInfo.worker.threadId}`);
|
|
99
101
|
}
|
|
100
|
-
this.
|
|
102
|
+
const path = this.resolvePath(threadInfo.path);
|
|
103
|
+
this.log.debug(`Starting thread ${threadInfo.name} from path ${path} type ${threadInfo.type}...`);
|
|
101
104
|
threadInfo.lastStarted = undefined;
|
|
102
105
|
threadInfo.lastStopped = undefined;
|
|
103
106
|
threadInfo.lastDuration = undefined;
|
|
104
|
-
threadInfo.worker = this.createESMWorker(threadInfo.name,
|
|
107
|
+
threadInfo.worker = this.createESMWorker(threadInfo.name, path, { ...workerData, debug: this.debug, verbose: this.verbose, logLevel: this.log.logLevel }, argv, env, execArgv, pipedOutput);
|
|
105
108
|
const worker = threadInfo.worker;
|
|
106
109
|
worker.once('online', () => {
|
|
107
110
|
threadInfo.runCount = (threadInfo.runCount ?? 0) + 1;
|
|
108
111
|
threadInfo.lastStarted = Date.now();
|
|
109
112
|
threadInfo.lastSeen = Date.now();
|
|
110
|
-
this.log.
|
|
113
|
+
this.log.debug(`Thread ${threadInfo.name} is online started at ${new Date(threadInfo.lastStarted).toISOString()} with thread id ${worker.threadId}`);
|
|
111
114
|
});
|
|
112
115
|
worker.once('exit', () => {
|
|
113
116
|
const stoppedAt = Date.now();
|
|
@@ -115,18 +118,19 @@ export class ThreadsManager {
|
|
|
115
118
|
threadInfo.lastDuration = Math.max(0, stoppedAt - (threadInfo.lastStarted ?? stoppedAt));
|
|
116
119
|
threadInfo.worker = undefined;
|
|
117
120
|
threadInfo.lastSeen = Date.now();
|
|
118
|
-
this.log.
|
|
121
|
+
this.log.debug(`Thread ${threadInfo.name} has exited at ${new Date(threadInfo.lastStopped).toISOString()} after running for ${threadInfo.lastDuration} ms`);
|
|
119
122
|
});
|
|
120
123
|
worker.on('message', (message) => {
|
|
121
124
|
threadInfo.lastSeen = Date.now();
|
|
122
|
-
|
|
125
|
+
if (this.verbose)
|
|
126
|
+
this.log.debug(`Thread ${threadInfo.name} sent a message at ${new Date().toISOString()}: ${debugStringify(message)}`);
|
|
123
127
|
if (message.type === 'log') {
|
|
124
128
|
AnsiLogger.create({ logName: threadInfo.name, logNameColor: MAGENTA, logTimestampFormat: 4, logLevel: this.log.logLevel }).log(message.logLevel, message.message);
|
|
125
129
|
}
|
|
126
130
|
});
|
|
127
131
|
worker.on('messageerror', () => {
|
|
128
132
|
threadInfo.errorCount = (threadInfo.errorCount ?? 0) + 1;
|
|
129
|
-
this.log.error(`Thread ${threadInfo.name} encountered a message error at ${new Date().toISOString()}
|
|
133
|
+
this.log.error(`Thread ${threadInfo.name} encountered a message error at ${new Date().toISOString()}`);
|
|
130
134
|
});
|
|
131
135
|
worker.once('error', () => {
|
|
132
136
|
threadInfo.errorCount = (threadInfo.errorCount ?? 0) + 1;
|
|
@@ -136,7 +140,7 @@ export class ThreadsManager {
|
|
|
136
140
|
threadInfo.worker = undefined;
|
|
137
141
|
this.log.error(`Thread ${threadInfo.name} encountered an error at ${new Date(threadInfo.lastStopped).toISOString()} after running for ${threadInfo.lastDuration} ms`);
|
|
138
142
|
});
|
|
139
|
-
this.log.
|
|
143
|
+
this.log.debug(`Started thread ${threadInfo.name} from path ${path} type ${threadInfo.type} with thread id ${worker.threadId}`);
|
|
140
144
|
return threadInfo.worker;
|
|
141
145
|
}
|
|
142
146
|
resolvePath(fileName) {
|
|
@@ -154,7 +158,7 @@ export class ThreadsManager {
|
|
|
154
158
|
createESMWorker(name, relativePath, workerData, argv, env, execArgv, pipedOutput = false) {
|
|
155
159
|
const fileURL = pathToFileURL(resolve(relativePath));
|
|
156
160
|
const options = {
|
|
157
|
-
workerData: { ...workerData, threadName: name, debug: this.debug, verbose: this.verbose, logLevel: this.log.logLevel },
|
|
161
|
+
workerData: { ...workerData, threadName: name, debug: this.debug, verbose: this.verbose, logLevel: this.log.logLevel, tracker: this.tracker },
|
|
158
162
|
type: 'module',
|
|
159
163
|
name,
|
|
160
164
|
argv: argv ?? process.argv.slice(2),
|
|
@@ -164,7 +168,7 @@ export class ThreadsManager {
|
|
|
164
168
|
stderr: pipedOutput,
|
|
165
169
|
};
|
|
166
170
|
if (this.verbose)
|
|
167
|
-
this.log.debug(`Creating ESM Worker ${name} with file URL
|
|
171
|
+
this.log.debug(`Creating ESM Worker ${name} with file URL ${fileURL.href} and options ${debugStringify(options)}`);
|
|
168
172
|
return new Worker(fileURL, options);
|
|
169
173
|
}
|
|
170
174
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { inspectError } from '@matterbridge/utils/error';
|
|
2
2
|
import { checkUpdates } from './checkUpdates.js';
|
|
3
3
|
import { WorkerWrapper } from './workerWrapper.js';
|
|
4
|
-
new WorkerWrapper('
|
|
4
|
+
new WorkerWrapper('CheckUpdates', async (worker) => {
|
|
5
5
|
worker.logger("info", `Starting check updates...`);
|
|
6
6
|
let success = false;
|
|
7
7
|
try {
|
|
@@ -1,12 +1,29 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isSpawnWorkerData } from '@matterbridge/types';
|
|
2
2
|
import { spawnCommand } from './spawnCommand.js';
|
|
3
3
|
import { WorkerWrapper } from './workerWrapper.js';
|
|
4
|
-
new WorkerWrapper('
|
|
5
|
-
worker.
|
|
6
|
-
|
|
4
|
+
new WorkerWrapper('SpawnCommand', async (worker) => {
|
|
5
|
+
if (!isSpawnWorkerData(worker.workerData)) {
|
|
6
|
+
worker.logger("error", `SpawnCommand invalid parameters`);
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
worker.logger("info", `Starting spawn command ${worker.workerData.command} with args ${worker.workerData.args.join(' ')} and package command ${worker.workerData.packageCommand} for package ${worker.workerData.packageName}...`);
|
|
10
|
+
const success = await spawnCommand(worker.workerData.command, worker.workerData.args, worker.workerData.packageCommand, worker.workerData.packageName);
|
|
7
11
|
if (success)
|
|
8
|
-
worker.logger("info", `Spawn command ${workerData.command} with args ${workerData.args.join(' ')} executed successfully`);
|
|
12
|
+
worker.logger("info", `Spawn command ${worker.workerData.command} with args ${worker.workerData.args.join(' ')} executed successfully`);
|
|
9
13
|
else
|
|
10
|
-
worker.logger("error", `Spawn command ${workerData.command} with args ${workerData.args.join(' ')} failed`);
|
|
14
|
+
worker.logger("error", `Spawn command ${worker.workerData.command} with args ${worker.workerData.args.join(' ')} failed`);
|
|
15
|
+
worker.server.respond({
|
|
16
|
+
type: 'manager_spawn_response',
|
|
17
|
+
src: `manager`,
|
|
18
|
+
dst: 'all',
|
|
19
|
+
id: worker.server.getUniqueId(),
|
|
20
|
+
result: {
|
|
21
|
+
command: worker.workerData.command,
|
|
22
|
+
args: worker.workerData.args,
|
|
23
|
+
packageCommand: worker.workerData.packageCommand,
|
|
24
|
+
packageName: worker.workerData.packageName,
|
|
25
|
+
success,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
11
28
|
return success;
|
|
12
29
|
});
|
package/dist/workerWrapper.d.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
import type { ParentPortMessage } from '@matterbridge/types';
|
|
1
|
+
import type { ParentPortMessage, ThreadNames, WorkerData } from '@matterbridge/types';
|
|
2
|
+
import type { Tracker } from '@matterbridge/utils/tracker';
|
|
2
3
|
import { AnsiLogger, LogLevel } from 'node-ansi-logger';
|
|
3
4
|
import { BroadcastServer } from './broadcastServer.js';
|
|
4
5
|
export declare class WorkerWrapper {
|
|
5
|
-
name:
|
|
6
|
+
name: ThreadNames;
|
|
6
7
|
debug: boolean;
|
|
7
8
|
verbose: boolean;
|
|
9
|
+
useTracker: boolean;
|
|
8
10
|
log: AnsiLogger;
|
|
9
11
|
server: BroadcastServer;
|
|
10
|
-
|
|
12
|
+
workerData: WorkerData | null;
|
|
13
|
+
tracker: Tracker | undefined;
|
|
14
|
+
constructor(name: ThreadNames, callback: (worker: WorkerWrapper) => Promise<boolean>);
|
|
11
15
|
destroy(success: boolean): void;
|
|
12
16
|
parentPost(message: ParentPortMessage): void;
|
|
13
17
|
parentLog(logName: string | undefined, logLevel: LogLevel, message: string): void;
|
package/dist/workerWrapper.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
if (process.argv.includes('--loader') || process.argv.includes('-loader'))
|
|
2
|
+
console.log('\u001B[32mWorkerWrapper loaded.\u001B[40;0m');
|
|
2
3
|
import { isMainThread, parentPort, threadId, workerData } from 'node:worker_threads';
|
|
3
4
|
import { hasParameter } from '@matterbridge/utils/cli';
|
|
5
|
+
import { formatBytes } from '@matterbridge/utils/format';
|
|
4
6
|
import { AnsiLogger, debugStringify, MAGENTA } from 'node-ansi-logger';
|
|
5
7
|
import { BroadcastServer } from './broadcastServer.js';
|
|
6
8
|
import { ThreadsManager } from './threadsManager.js';
|
|
@@ -8,40 +10,60 @@ export class WorkerWrapper {
|
|
|
8
10
|
name;
|
|
9
11
|
debug = hasParameter('debug') || hasParameter('verbose') || hasParameter('debug-threads') || hasParameter('verbose-threads');
|
|
10
12
|
verbose = hasParameter('verbose') || hasParameter('verbose-threads');
|
|
13
|
+
useTracker = hasParameter('tracker') || hasParameter('tracker-threads');
|
|
11
14
|
log;
|
|
12
15
|
server;
|
|
16
|
+
workerData = workerData;
|
|
17
|
+
tracker;
|
|
13
18
|
constructor(name, callback) {
|
|
14
19
|
this.name = name;
|
|
20
|
+
if (this.workerData) {
|
|
21
|
+
this.debug = this.workerData.debug || this.debug;
|
|
22
|
+
this.verbose = this.workerData.verbose || this.verbose;
|
|
23
|
+
this.useTracker = this.workerData.tracker || this.useTracker;
|
|
24
|
+
}
|
|
25
|
+
if (this.useTracker) {
|
|
26
|
+
void import('@matterbridge/utils/tracker')
|
|
27
|
+
.then(({ Tracker }) => {
|
|
28
|
+
this.tracker = new Tracker(`Thread${this.name}`, this.debug, this.verbose);
|
|
29
|
+
this.tracker.start();
|
|
30
|
+
return undefined;
|
|
31
|
+
})
|
|
32
|
+
.catch((err) => {
|
|
33
|
+
if (this.debug)
|
|
34
|
+
console.error(`WorkerWrapper ${this.name}: failed to load Tracker`, err);
|
|
35
|
+
return undefined;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
15
38
|
this.log = new AnsiLogger({
|
|
16
|
-
logName: name,
|
|
39
|
+
logName: this.name,
|
|
17
40
|
logNameColor: MAGENTA,
|
|
18
41
|
logTimestampFormat: 4,
|
|
19
42
|
logLevel: this.debug ? "debug" : "info",
|
|
20
43
|
});
|
|
21
44
|
this.server = new BroadcastServer('matterbridge', this.log);
|
|
22
|
-
if (!isMainThread && parentPort) {
|
|
45
|
+
if (!isMainThread && parentPort && this.workerData) {
|
|
23
46
|
parentPort.on('message', (message) => {
|
|
24
47
|
if (this.debug)
|
|
25
|
-
this.log.debug(`Worker ${
|
|
48
|
+
this.log.debug(`Worker ${this.name}:${threadId} received message from parent: ${debugStringify(message)}`);
|
|
26
49
|
switch (message.type) {
|
|
27
50
|
case 'ping':
|
|
28
|
-
this.parentLog(
|
|
29
|
-
this.parentPost({ type: 'pong', threadId, threadName:
|
|
30
|
-
this.parentLog(
|
|
51
|
+
this.parentLog(this.name, "debug", `Worker ${this.name}:${threadId} received ping message type from parent: ${debugStringify(message)}`);
|
|
52
|
+
this.parentPost({ type: 'pong', threadId, threadName: this.name });
|
|
53
|
+
this.parentLog(this.name, "debug", `Worker ${this.name}:${threadId} sent pong message type to parent: ${debugStringify(message)}`);
|
|
31
54
|
break;
|
|
32
55
|
case 'pong':
|
|
33
|
-
this.parentLog(
|
|
56
|
+
this.parentLog(this.name, "debug", `Worker ${this.name}:${threadId} received pong message type from parent: ${debugStringify(message)}`);
|
|
34
57
|
break;
|
|
35
58
|
default:
|
|
36
|
-
this.parentLog(
|
|
59
|
+
this.parentLog(this.name, "warn", `Worker ${this.name}:${threadId} received unknown message type from parent: ${debugStringify(message)}`);
|
|
37
60
|
}
|
|
38
61
|
});
|
|
39
62
|
}
|
|
40
|
-
if (!isMainThread && parentPort && workerData) {
|
|
41
|
-
name
|
|
42
|
-
this.parentPost({ type: 'init', threadId, threadName: workerData.threadName, success: true });
|
|
63
|
+
if (!isMainThread && parentPort && this.workerData) {
|
|
64
|
+
this.parentPost({ type: 'init', threadId, threadName: this.name, memoryUsage: process.memoryUsage(), success: true });
|
|
43
65
|
if (this.debug)
|
|
44
|
-
this.parentLog(name, "info", `Worker ${
|
|
66
|
+
this.parentLog(this.name, "info", `Worker ${this.name}:${threadId} initialized.`);
|
|
45
67
|
}
|
|
46
68
|
if (this.verbose)
|
|
47
69
|
this.logWorkerInfo(this.log, false);
|
|
@@ -51,28 +73,30 @@ export class WorkerWrapper {
|
|
|
51
73
|
});
|
|
52
74
|
}
|
|
53
75
|
destroy(success) {
|
|
76
|
+
if (this.tracker)
|
|
77
|
+
this.tracker.stop();
|
|
54
78
|
this.server.close();
|
|
55
|
-
if (!isMainThread && parentPort && workerData) {
|
|
79
|
+
if (!isMainThread && parentPort && this.workerData) {
|
|
56
80
|
if (this.debug)
|
|
57
|
-
this.parentLog(this.name, "info", `Worker ${
|
|
58
|
-
this.parentPost({ type: 'exit', threadId, threadName:
|
|
81
|
+
this.parentLog(this.name, "info", `Worker ${this.name}:${threadId} exiting with success: ${success}.`);
|
|
82
|
+
this.parentPost({ type: 'exit', threadId, threadName: this.name, memoryUsage: process.memoryUsage(), success });
|
|
59
83
|
parentPort.close();
|
|
60
84
|
}
|
|
61
85
|
}
|
|
62
86
|
parentPost(message) {
|
|
63
87
|
if (!parentPort)
|
|
64
|
-
throw new Error(`WorkerServer ${
|
|
88
|
+
throw new Error(`WorkerServer ${this.name}: parentPort is not available.`);
|
|
65
89
|
parentPort.postMessage(message);
|
|
66
90
|
if (this.debug)
|
|
67
|
-
this.log.debug(`Worker ${
|
|
91
|
+
this.log.debug(`Worker ${this.name}:${threadId} sent message to parent: ${debugStringify(message)}`);
|
|
68
92
|
}
|
|
69
93
|
parentLog(logName, logLevel, message) {
|
|
70
94
|
if (!parentPort)
|
|
71
|
-
throw new Error(`WorkerServer ${
|
|
72
|
-
const logMessage = { type: 'log', threadId, threadName:
|
|
95
|
+
throw new Error(`WorkerServer ${this.name}: parentPort is not available.`);
|
|
96
|
+
const logMessage = { type: 'log', threadId, threadName: this.name, logName, logLevel, message };
|
|
73
97
|
parentPort.postMessage(logMessage);
|
|
74
98
|
if (this.debug)
|
|
75
|
-
this.log.debug(`Worker ${
|
|
99
|
+
this.log.debug(`Worker ${this.name}:${threadId} sent log to parent: ${logName} ${logLevel} ${message}`);
|
|
76
100
|
}
|
|
77
101
|
logger(level, message) {
|
|
78
102
|
if (!isMainThread && parentPort)
|
|
@@ -81,11 +105,12 @@ export class WorkerWrapper {
|
|
|
81
105
|
AnsiLogger.create({ logName: this.name, logNameColor: MAGENTA, logTimestampFormat: 4, logLevel: ThreadsManager.logLevel }).log(level, message);
|
|
82
106
|
}
|
|
83
107
|
logWorkerInfo(log, logEnv = false) {
|
|
84
|
-
log.debug(`${isMainThread ? 'Main thread' : 'Worker thread'}: ${
|
|
108
|
+
log.debug(`${isMainThread ? 'Main thread' : 'Worker thread'}: ${this.name}:${threadId} Pid: ${process.pid}`);
|
|
85
109
|
log.debug(`ParentPort: ${parentPort ? 'active' : 'not active'}`);
|
|
86
|
-
log.debug(`WorkerData: ${workerData ? debugStringify(workerData) : 'none'}`);
|
|
110
|
+
log.debug(`WorkerData: ${this.workerData ? debugStringify(this.workerData) : 'none'}`);
|
|
87
111
|
const argv = process.argv.slice(2);
|
|
88
112
|
log.debug(`Argv: ${argv.length ? argv.join(' ') : 'none'}`);
|
|
89
|
-
log.debug(`Env: ${logEnv ?
|
|
113
|
+
log.debug(`Env: ${logEnv ? debugStringify(process.env) : 'not logged'}`);
|
|
114
|
+
log.debug(`Memory: ${formatBytes(process.memoryUsage().heapTotal)} total, ${formatBytes(process.memoryUsage().heapUsed)} used`);
|
|
90
115
|
}
|
|
91
116
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@matterbridge/thread",
|
|
3
|
-
"version": "3.6.1-dev-
|
|
3
|
+
"version": "3.6.1-dev-20260310-7887380",
|
|
4
4
|
"description": "Matterbridge thread library",
|
|
5
5
|
"author": "https://github.com/Luligu",
|
|
6
6
|
"homepage": "https://matterbridge.io/",
|
|
@@ -69,8 +69,8 @@
|
|
|
69
69
|
"CHANGELOG.md"
|
|
70
70
|
],
|
|
71
71
|
"dependencies": {
|
|
72
|
-
"@matterbridge/types": "3.6.1-dev-
|
|
73
|
-
"@matterbridge/utils": "3.6.1-dev-
|
|
72
|
+
"@matterbridge/types": "3.6.1-dev-20260310-7887380",
|
|
73
|
+
"@matterbridge/utils": "3.6.1-dev-20260310-7887380",
|
|
74
74
|
"node-ansi-logger": "3.2.0"
|
|
75
75
|
}
|
|
76
76
|
}
|