@livekit/agents 0.4.5 → 0.5.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 +17 -0
- package/dist/audio.cjs +77 -0
- package/dist/audio.cjs.map +1 -0
- package/dist/audio.js +48 -37
- package/dist/audio.js.map +1 -1
- package/dist/cli.cjs +131 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.js +96 -122
- package/dist/cli.js.map +1 -1
- package/dist/generator.cjs +36 -0
- package/dist/generator.cjs.map +1 -0
- package/dist/generator.js +8 -22
- package/dist/generator.js.map +1 -1
- package/dist/http_server.cjs +72 -0
- package/dist/http_server.cjs.map +1 -0
- package/dist/http_server.d.ts +1 -1
- package/dist/http_server.js +44 -47
- package/dist/http_server.js.map +1 -1
- package/dist/index.cjs +78 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +26 -28
- package/dist/index.js.map +1 -1
- package/dist/ipc/job_executor.cjs +33 -0
- package/dist/ipc/job_executor.cjs.map +1 -0
- package/dist/ipc/job_executor.js +7 -4
- package/dist/ipc/job_executor.js.map +1 -1
- package/dist/ipc/job_main.cjs +147 -0
- package/dist/ipc/job_main.cjs.map +1 -0
- package/dist/ipc/job_main.d.ts +1 -1
- package/dist/ipc/job_main.js +103 -103
- package/dist/ipc/job_main.js.map +1 -1
- package/dist/ipc/message.cjs +17 -0
- package/dist/ipc/message.cjs.map +1 -0
- package/dist/ipc/message.js +0 -1
- package/dist/ipc/message.js.map +1 -1
- package/dist/ipc/proc_job_executor.cjs +174 -0
- package/dist/ipc/proc_job_executor.cjs.map +1 -0
- package/dist/ipc/proc_job_executor.js +130 -126
- package/dist/ipc/proc_job_executor.js.map +1 -1
- package/dist/ipc/proc_pool.cjs +126 -0
- package/dist/ipc/proc_pool.cjs.map +1 -0
- package/dist/ipc/proc_pool.js +93 -96
- package/dist/ipc/proc_pool.js.map +1 -1
- package/dist/job.cjs +230 -0
- package/dist/job.cjs.map +1 -0
- package/dist/job.js +195 -198
- package/dist/job.js.map +1 -1
- package/dist/llm/chat_context.cjs +131 -0
- package/dist/llm/chat_context.cjs.map +1 -0
- package/dist/llm/chat_context.js +98 -86
- package/dist/llm/chat_context.js.map +1 -1
- package/dist/llm/function_context.cjs +103 -0
- package/dist/llm/function_context.cjs.map +1 -0
- package/dist/llm/function_context.js +72 -81
- package/dist/llm/function_context.js.map +1 -1
- package/dist/llm/function_context.test.cjs +218 -0
- package/dist/llm/function_context.test.cjs.map +1 -0
- package/dist/llm/function_context.test.js +209 -210
- package/dist/llm/function_context.test.js.map +1 -1
- package/dist/llm/index.cjs +43 -0
- package/dist/llm/index.cjs.map +1 -0
- package/dist/llm/index.js +22 -6
- package/dist/llm/index.js.map +1 -1
- package/dist/llm/llm.cjs +76 -0
- package/dist/llm/llm.cjs.map +1 -0
- package/dist/llm/llm.js +48 -42
- package/dist/llm/llm.js.map +1 -1
- package/dist/log.cjs +57 -0
- package/dist/log.cjs.map +1 -0
- package/dist/log.js +27 -26
- package/dist/log.js.map +1 -1
- package/dist/multimodal/agent_playout.cjs +228 -0
- package/dist/multimodal/agent_playout.cjs.map +1 -0
- package/dist/multimodal/agent_playout.d.ts +1 -1
- package/dist/multimodal/agent_playout.js +193 -180
- package/dist/multimodal/agent_playout.js.map +1 -1
- package/dist/multimodal/index.cjs +25 -0
- package/dist/multimodal/index.cjs.map +1 -0
- package/dist/multimodal/index.js +2 -5
- package/dist/multimodal/index.js.map +1 -1
- package/dist/multimodal/multimodal_agent.cjs +404 -0
- package/dist/multimodal/multimodal_agent.cjs.map +1 -0
- package/dist/multimodal/multimodal_agent.d.ts +2 -2
- package/dist/multimodal/multimodal_agent.d.ts.map +1 -1
- package/dist/multimodal/multimodal_agent.js +351 -303
- package/dist/multimodal/multimodal_agent.js.map +1 -1
- package/dist/pipeline/agent_output.cjs +172 -0
- package/dist/pipeline/agent_output.cjs.map +1 -0
- package/dist/pipeline/agent_output.js +136 -138
- package/dist/pipeline/agent_output.js.map +1 -1
- package/dist/pipeline/agent_playout.cjs +169 -0
- package/dist/pipeline/agent_playout.cjs.map +1 -0
- package/dist/pipeline/agent_playout.js +126 -136
- package/dist/pipeline/agent_playout.js.map +1 -1
- package/dist/pipeline/human_input.cjs +158 -0
- package/dist/pipeline/human_input.cjs.map +1 -0
- package/dist/pipeline/human_input.js +124 -125
- package/dist/pipeline/human_input.js.map +1 -1
- package/dist/pipeline/index.cjs +31 -0
- package/dist/pipeline/index.cjs.map +1 -0
- package/dist/pipeline/index.js +8 -4
- package/dist/pipeline/index.js.map +1 -1
- package/dist/pipeline/pipeline_agent.cjs +642 -0
- package/dist/pipeline/pipeline_agent.cjs.map +1 -0
- package/dist/pipeline/pipeline_agent.d.ts +1 -0
- package/dist/pipeline/pipeline_agent.d.ts.map +1 -1
- package/dist/pipeline/pipeline_agent.js +595 -650
- package/dist/pipeline/pipeline_agent.js.map +1 -1
- package/dist/pipeline/speech_handle.cjs +128 -0
- package/dist/pipeline/speech_handle.cjs.map +1 -0
- package/dist/pipeline/speech_handle.js +102 -100
- package/dist/pipeline/speech_handle.js.map +1 -1
- package/dist/plugin.cjs +46 -0
- package/dist/plugin.cjs.map +1 -0
- package/dist/plugin.js +20 -20
- package/dist/plugin.js.map +1 -1
- package/dist/stt/index.cjs +38 -0
- package/dist/stt/index.cjs.map +1 -0
- package/dist/stt/index.js +13 -5
- package/dist/stt/index.js.map +1 -1
- package/dist/stt/stream_adapter.cjs +87 -0
- package/dist/stt/stream_adapter.cjs.map +1 -0
- package/dist/stt/stream_adapter.js +58 -55
- package/dist/stt/stream_adapter.js.map +1 -1
- package/dist/stt/stt.cjs +98 -0
- package/dist/stt/stt.cjs.map +1 -0
- package/dist/stt/stt.js +63 -98
- package/dist/stt/stt.js.map +1 -1
- package/dist/tokenize/basic/basic.cjs +98 -0
- package/dist/tokenize/basic/basic.cjs.map +1 -0
- package/dist/tokenize/basic/basic.js +56 -45
- package/dist/tokenize/basic/basic.js.map +1 -1
- package/dist/tokenize/basic/hyphenator.cjs +425 -0
- package/dist/tokenize/basic/hyphenator.cjs.map +1 -0
- package/dist/tokenize/basic/hyphenator.js +66 -82
- package/dist/tokenize/basic/hyphenator.js.map +1 -1
- package/dist/tokenize/basic/index.cjs +35 -0
- package/dist/tokenize/basic/index.cjs.map +1 -0
- package/dist/tokenize/basic/index.js +7 -4
- package/dist/tokenize/basic/index.js.map +1 -1
- package/dist/tokenize/basic/paragraph.cjs +57 -0
- package/dist/tokenize/basic/paragraph.cjs.map +1 -0
- package/dist/tokenize/basic/paragraph.js +30 -35
- package/dist/tokenize/basic/paragraph.js.map +1 -1
- package/dist/tokenize/basic/sentence.cjs +83 -0
- package/dist/tokenize/basic/sentence.cjs.map +1 -0
- package/dist/tokenize/basic/sentence.js +56 -57
- package/dist/tokenize/basic/sentence.js.map +1 -1
- package/dist/tokenize/basic/word.cjs +44 -0
- package/dist/tokenize/basic/word.cjs.map +1 -0
- package/dist/tokenize/basic/word.js +17 -20
- package/dist/tokenize/basic/word.js.map +1 -1
- package/dist/tokenize/index.cjs +55 -0
- package/dist/tokenize/index.cjs.map +1 -0
- package/dist/tokenize/index.js +18 -7
- package/dist/tokenize/index.js.map +1 -1
- package/dist/tokenize/token_stream.cjs +164 -0
- package/dist/tokenize/token_stream.cjs.map +1 -0
- package/dist/tokenize/token_stream.js +133 -139
- package/dist/tokenize/token_stream.js.map +1 -1
- package/dist/tokenize/tokenizer.cjs +184 -0
- package/dist/tokenize/tokenizer.cjs.map +1 -0
- package/dist/tokenize/tokenizer.js +138 -99
- package/dist/tokenize/tokenizer.js.map +1 -1
- package/dist/transcription.cjs +131 -0
- package/dist/transcription.cjs.map +1 -0
- package/dist/transcription.d.ts +2 -0
- package/dist/transcription.d.ts.map +1 -1
- package/dist/transcription.js +99 -93
- package/dist/transcription.js.map +1 -1
- package/dist/tts/index.cjs +38 -0
- package/dist/tts/index.cjs.map +1 -0
- package/dist/tts/index.js +13 -5
- package/dist/tts/index.js.map +1 -1
- package/dist/tts/stream_adapter.cjs +78 -0
- package/dist/tts/stream_adapter.cjs.map +1 -0
- package/dist/tts/stream_adapter.js +50 -47
- package/dist/tts/stream_adapter.js.map +1 -1
- package/dist/tts/tts.cjs +127 -0
- package/dist/tts/tts.cjs.map +1 -0
- package/dist/tts/tts.js +90 -120
- package/dist/tts/tts.js.map +1 -1
- package/dist/utils.cjs +284 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.js +242 -247
- package/dist/utils.js.map +1 -1
- package/dist/vad.cjs +92 -0
- package/dist/vad.cjs.map +1 -0
- package/dist/vad.js +57 -52
- package/dist/vad.js.map +1 -1
- package/dist/version.cjs +29 -0
- package/dist/version.cjs.map +1 -0
- package/dist/version.js +4 -4
- package/dist/version.js.map +1 -1
- package/dist/worker.cjs +576 -0
- package/dist/worker.cjs.map +1 -0
- package/dist/worker.d.ts +1 -1
- package/dist/worker.js +511 -484
- package/dist/worker.js.map +1 -1
- package/package.json +23 -7
- package/src/ipc/job_main.ts +66 -64
- package/src/multimodal/multimodal_agent.ts +29 -2
- package/src/pipeline/pipeline_agent.ts +25 -24
- package/src/transcription.ts +5 -0
- package/.turbo/turbo-build.log +0 -4
- package/CHANGELOG.md +0 -165
- package/api-extractor.json +0 -20
- package/tsconfig.json +0 -16
- package/tsconfig.tsbuildinfo +0 -1
package/dist/worker.js
CHANGED
|
@@ -1,516 +1,543 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
JobType,
|
|
3
|
+
ParticipantPermission,
|
|
4
|
+
ServerMessage,
|
|
5
|
+
WorkerMessage,
|
|
6
|
+
WorkerStatus
|
|
7
|
+
} from "@livekit/protocol";
|
|
8
|
+
import { AccessToken, RoomServiceClient } from "livekit-server-sdk";
|
|
9
|
+
import { EventEmitter } from "node:events";
|
|
10
|
+
import os from "node:os";
|
|
11
|
+
import { WebSocket } from "ws";
|
|
12
|
+
import { HTTPServer } from "./http_server.js";
|
|
13
|
+
import { ProcPool } from "./ipc/proc_pool.js";
|
|
14
|
+
import { JobRequest } from "./job.js";
|
|
15
|
+
import { log } from "./log.js";
|
|
16
|
+
import { Future } from "./utils.js";
|
|
17
|
+
import { version } from "./version.js";
|
|
12
18
|
const MAX_RECONNECT_ATTEMPTS = 10;
|
|
13
|
-
const ASSIGNMENT_TIMEOUT = 7.5 *
|
|
14
|
-
const UPDATE_LOAD_INTERVAL = 2.5 *
|
|
19
|
+
const ASSIGNMENT_TIMEOUT = 7.5 * 1e3;
|
|
20
|
+
const UPDATE_LOAD_INTERVAL = 2.5 * 1e3;
|
|
15
21
|
class Default {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return Infinity;
|
|
22
|
-
}
|
|
22
|
+
static loadThreshold(production) {
|
|
23
|
+
if (production) {
|
|
24
|
+
return 0.65;
|
|
25
|
+
} else {
|
|
26
|
+
return Infinity;
|
|
23
27
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
28
|
+
}
|
|
29
|
+
static numIdleProcesses(production) {
|
|
30
|
+
if (production) {
|
|
31
|
+
return 3;
|
|
32
|
+
} else {
|
|
33
|
+
return 0;
|
|
31
34
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
35
|
+
}
|
|
36
|
+
static port(production) {
|
|
37
|
+
if (production) {
|
|
38
|
+
return 8081;
|
|
39
|
+
} else {
|
|
40
|
+
return 0;
|
|
39
41
|
}
|
|
42
|
+
}
|
|
40
43
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
44
|
+
class MissingCredentialsError extends Error {
|
|
45
|
+
constructor(msg) {
|
|
46
|
+
super(msg);
|
|
47
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
48
|
+
}
|
|
47
49
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
50
|
+
class WorkerError extends Error {
|
|
51
|
+
constructor(msg) {
|
|
52
|
+
super(msg);
|
|
53
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
54
|
+
}
|
|
54
55
|
}
|
|
55
|
-
|
|
56
|
-
export const defaultInitializeProcessFunc = (_) => _;
|
|
56
|
+
const defaultInitializeProcessFunc = (_) => _;
|
|
57
57
|
const defaultRequestFunc = async (ctx) => {
|
|
58
|
-
|
|
58
|
+
await ctx.accept();
|
|
59
59
|
};
|
|
60
60
|
const defaultCpuLoad = async () => {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
61
|
+
return new Promise((resolve) => {
|
|
62
|
+
const cpus1 = os.cpus();
|
|
63
|
+
setTimeout(() => {
|
|
64
|
+
const cpus2 = os.cpus();
|
|
65
|
+
let idle = 0;
|
|
66
|
+
let total = 0;
|
|
67
|
+
for (let i = 0; i < cpus1.length; i++) {
|
|
68
|
+
const cpu1 = cpus1[i].times;
|
|
69
|
+
const cpu2 = cpus2[i].times;
|
|
70
|
+
idle += cpu2.idle - cpu1.idle;
|
|
71
|
+
const total1 = Object.values(cpu1).reduce((acc, i2) => acc + i2, 0);
|
|
72
|
+
const total2 = Object.values(cpu2).reduce((acc, i2) => acc + i2, 0);
|
|
73
|
+
total += total2 - total1;
|
|
74
|
+
}
|
|
75
|
+
resolve(+(1 - idle / total).toFixed(2));
|
|
76
|
+
}, UPDATE_LOAD_INTERVAL);
|
|
77
|
+
});
|
|
78
78
|
};
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
79
|
+
class WorkerPermissions {
|
|
80
|
+
canPublish;
|
|
81
|
+
canSubscribe;
|
|
82
|
+
canPublishData;
|
|
83
|
+
canUpdateMetadata;
|
|
84
|
+
canPublishSources;
|
|
85
|
+
hidden;
|
|
86
|
+
constructor(canPublish = true, canSubscribe = true, canPublishData = true, canUpdateMetadata = true, canPublishSources = [], hidden = false) {
|
|
87
|
+
this.canPublish = canPublish;
|
|
88
|
+
this.canSubscribe = canSubscribe;
|
|
89
|
+
this.canPublishData = canPublishData;
|
|
90
|
+
this.canUpdateMetadata = canUpdateMetadata;
|
|
91
|
+
this.canPublishSources = canPublishSources;
|
|
92
|
+
this.hidden = hidden;
|
|
93
|
+
}
|
|
95
94
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
this.maxRetry = maxRetry;
|
|
140
|
-
this.wsURL = wsURL;
|
|
141
|
-
this.apiKey = apiKey;
|
|
142
|
-
this.apiSecret = apiSecret;
|
|
143
|
-
this.host = host;
|
|
144
|
-
this.port = port || Default.port(production);
|
|
145
|
-
this.logLevel = logLevel;
|
|
146
|
-
this.production = production;
|
|
95
|
+
class WorkerOptions {
|
|
96
|
+
agent;
|
|
97
|
+
requestFunc;
|
|
98
|
+
loadFunc;
|
|
99
|
+
loadThreshold;
|
|
100
|
+
numIdleProcesses;
|
|
101
|
+
shutdownProcessTimeout;
|
|
102
|
+
initializeProcessTimeout;
|
|
103
|
+
permissions;
|
|
104
|
+
agentName;
|
|
105
|
+
workerType;
|
|
106
|
+
maxRetry;
|
|
107
|
+
wsURL;
|
|
108
|
+
apiKey;
|
|
109
|
+
apiSecret;
|
|
110
|
+
host;
|
|
111
|
+
port;
|
|
112
|
+
logLevel;
|
|
113
|
+
production;
|
|
114
|
+
/** @param options */
|
|
115
|
+
constructor({
|
|
116
|
+
agent,
|
|
117
|
+
requestFunc = defaultRequestFunc,
|
|
118
|
+
loadFunc = defaultCpuLoad,
|
|
119
|
+
loadThreshold = void 0,
|
|
120
|
+
numIdleProcesses = void 0,
|
|
121
|
+
shutdownProcessTimeout = 60 * 1e3,
|
|
122
|
+
initializeProcessTimeout = 10 * 1e3,
|
|
123
|
+
permissions = new WorkerPermissions(),
|
|
124
|
+
agentName = "",
|
|
125
|
+
workerType = JobType.JT_ROOM,
|
|
126
|
+
maxRetry = MAX_RECONNECT_ATTEMPTS,
|
|
127
|
+
wsURL = "ws://localhost:7880",
|
|
128
|
+
apiKey = void 0,
|
|
129
|
+
apiSecret = void 0,
|
|
130
|
+
host = "localhost",
|
|
131
|
+
port = void 0,
|
|
132
|
+
logLevel = "info",
|
|
133
|
+
production = false
|
|
134
|
+
}) {
|
|
135
|
+
this.agent = agent;
|
|
136
|
+
if (!this.agent) {
|
|
137
|
+
throw new Error("No Agent file was passed to the worker");
|
|
147
138
|
}
|
|
139
|
+
this.requestFunc = requestFunc;
|
|
140
|
+
this.loadFunc = loadFunc;
|
|
141
|
+
this.loadThreshold = loadThreshold || Default.loadThreshold(production);
|
|
142
|
+
this.numIdleProcesses = numIdleProcesses || Default.numIdleProcesses(production);
|
|
143
|
+
this.shutdownProcessTimeout = shutdownProcessTimeout;
|
|
144
|
+
this.initializeProcessTimeout = initializeProcessTimeout;
|
|
145
|
+
this.permissions = permissions;
|
|
146
|
+
this.agentName = agentName;
|
|
147
|
+
this.workerType = workerType;
|
|
148
|
+
this.maxRetry = maxRetry;
|
|
149
|
+
this.wsURL = wsURL;
|
|
150
|
+
this.apiKey = apiKey;
|
|
151
|
+
this.apiSecret = apiSecret;
|
|
152
|
+
this.host = host;
|
|
153
|
+
this.port = port || Default.port(production);
|
|
154
|
+
this.logLevel = logLevel;
|
|
155
|
+
this.production = production;
|
|
156
|
+
}
|
|
148
157
|
}
|
|
149
158
|
class PendingAssignment {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
159
|
+
promise = new Promise((resolve) => {
|
|
160
|
+
this.resolve = resolve;
|
|
161
|
+
});
|
|
162
|
+
resolve(arg) {
|
|
163
|
+
arg;
|
|
164
|
+
}
|
|
156
165
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
166
|
+
class Worker {
|
|
167
|
+
#opts;
|
|
168
|
+
#procPool;
|
|
169
|
+
#id = "unregistered";
|
|
170
|
+
#closed = true;
|
|
171
|
+
#draining = false;
|
|
172
|
+
#connecting = false;
|
|
173
|
+
#tasks = [];
|
|
174
|
+
#pending = {};
|
|
175
|
+
#close = new Future();
|
|
176
|
+
event = new EventEmitter();
|
|
177
|
+
#session = void 0;
|
|
178
|
+
#httpServer;
|
|
179
|
+
#logger = log().child({ version });
|
|
180
|
+
/* @throws {@link MissingCredentialsError} if URL, API key or API secret are missing */
|
|
181
|
+
constructor(opts) {
|
|
182
|
+
opts.wsURL = opts.wsURL || process.env.LIVEKIT_URL || "";
|
|
183
|
+
opts.apiKey = opts.apiKey || process.env.LIVEKIT_API_KEY || "";
|
|
184
|
+
opts.apiSecret = opts.apiSecret || process.env.LIVEKIT_API_SECRET || "";
|
|
185
|
+
if (opts.wsURL === "")
|
|
186
|
+
throw new MissingCredentialsError(
|
|
187
|
+
"URL is required: Set LIVEKIT_URL, run with --url, or pass wsURL in WorkerOptions"
|
|
188
|
+
);
|
|
189
|
+
if (opts.apiKey === "")
|
|
190
|
+
throw new MissingCredentialsError(
|
|
191
|
+
"API Key is required: Set LIVEKIT_API_KEY, run with --api-key, or pass apiKey in WorkerOptions"
|
|
192
|
+
);
|
|
193
|
+
if (opts.apiSecret === "")
|
|
194
|
+
throw new MissingCredentialsError(
|
|
195
|
+
"API Secret is required: Set LIVEKIT_API_SECRET, run with --api-secret, or pass apiSecret in WorkerOptions"
|
|
196
|
+
);
|
|
197
|
+
this.#procPool = new ProcPool(
|
|
198
|
+
opts.agent,
|
|
199
|
+
opts.numIdleProcesses,
|
|
200
|
+
opts.initializeProcessTimeout,
|
|
201
|
+
opts.shutdownProcessTimeout
|
|
202
|
+
);
|
|
203
|
+
this.#opts = opts;
|
|
204
|
+
this.#httpServer = new HTTPServer(opts.host, opts.port);
|
|
205
|
+
}
|
|
206
|
+
/* @throws {@link WorkerError} if worker failed to connect or already running */
|
|
207
|
+
async run() {
|
|
208
|
+
if (!this.#closed) {
|
|
209
|
+
throw new WorkerError("worker is already running");
|
|
194
210
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
211
|
+
this.#logger.info("starting worker");
|
|
212
|
+
this.#closed = false;
|
|
213
|
+
this.#procPool.start();
|
|
214
|
+
const workerWS = async () => {
|
|
215
|
+
let retries = 0;
|
|
216
|
+
this.#connecting = true;
|
|
217
|
+
while (!this.#closed) {
|
|
218
|
+
const url = new URL(this.#opts.wsURL);
|
|
219
|
+
url.protocol = url.protocol.replace("http", "ws");
|
|
220
|
+
const token = new AccessToken(this.#opts.apiKey, this.#opts.apiSecret);
|
|
221
|
+
token.addGrant({ agent: true });
|
|
222
|
+
const jwt = await token.toJwt();
|
|
223
|
+
this.#session = new WebSocket(url + "agent", {
|
|
224
|
+
headers: { authorization: "Bearer " + jwt }
|
|
225
|
+
});
|
|
226
|
+
try {
|
|
227
|
+
await new Promise((resolve, reject) => {
|
|
228
|
+
this.#session.on("open", resolve);
|
|
229
|
+
this.#session.on("error", (error) => reject(error));
|
|
230
|
+
this.#session.on("close", (code) => reject(new Error(`WebSocket returned ${code}`)));
|
|
231
|
+
});
|
|
232
|
+
retries = 0;
|
|
233
|
+
this.#logger.debug("connected to LiveKit server");
|
|
234
|
+
this.#runWS(this.#session);
|
|
235
|
+
return;
|
|
236
|
+
} catch (e) {
|
|
237
|
+
if (this.#closed) return;
|
|
238
|
+
if (retries >= this.#opts.maxRetry) {
|
|
239
|
+
throw new WorkerError(
|
|
240
|
+
`failed to connect to LiveKit server after ${retries} attempts: ${e}`
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
retries++;
|
|
244
|
+
const delay = Math.min(retries * 2, 10);
|
|
245
|
+
this.#logger.warn(
|
|
246
|
+
`failed to connect to LiveKit server, retrying in ${delay} seconds: ${e} (${retries}/${this.#opts.maxRetry})`
|
|
247
|
+
);
|
|
248
|
+
await new Promise((resolve) => setTimeout(resolve, delay * 1e3));
|
|
199
249
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
try {
|
|
216
|
-
await new Promise((resolve, reject) => {
|
|
217
|
-
this.#session.on('open', resolve);
|
|
218
|
-
this.#session.on('error', (error) => reject(error));
|
|
219
|
-
this.#session.on('close', (code) => reject(new Error(`WebSocket returned ${code}`)));
|
|
220
|
-
});
|
|
221
|
-
retries = 0;
|
|
222
|
-
this.#logger.debug('connected to LiveKit server');
|
|
223
|
-
this.#runWS(this.#session);
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
catch (e) {
|
|
227
|
-
if (this.#closed)
|
|
228
|
-
return;
|
|
229
|
-
if (retries >= this.#opts.maxRetry) {
|
|
230
|
-
throw new WorkerError(`failed to connect to LiveKit server after ${retries} attempts: ${e}`);
|
|
231
|
-
}
|
|
232
|
-
retries++;
|
|
233
|
-
const delay = Math.min(retries * 2, 10);
|
|
234
|
-
this.#logger.warn(`failed to connect to LiveKit server, retrying in ${delay} seconds: ${e} (${retries}/${this.#opts.maxRetry})`);
|
|
235
|
-
await new Promise((resolve) => setTimeout(resolve, delay * 1000));
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
await Promise.all([workerWS(), this.#httpServer.run()]);
|
|
240
|
-
this.#close.resolve();
|
|
241
|
-
}
|
|
242
|
-
get id() {
|
|
243
|
-
return this.#id;
|
|
244
|
-
}
|
|
245
|
-
get activeJobs() {
|
|
246
|
-
return this.#procPool.processes
|
|
247
|
-
.filter((proc) => proc.runningJob)
|
|
248
|
-
.map((proc) => proc.runningJob);
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
await Promise.all([workerWS(), this.#httpServer.run()]);
|
|
253
|
+
this.#close.resolve();
|
|
254
|
+
}
|
|
255
|
+
get id() {
|
|
256
|
+
return this.#id;
|
|
257
|
+
}
|
|
258
|
+
get activeJobs() {
|
|
259
|
+
return this.#procPool.processes.filter((proc) => proc.runningJob).map((proc) => proc.runningJob);
|
|
260
|
+
}
|
|
261
|
+
/* @throws {@link WorkerError} if worker did not drain in time */
|
|
262
|
+
async drain(timeout) {
|
|
263
|
+
if (this.#draining) {
|
|
264
|
+
return;
|
|
249
265
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
266
|
+
this.#logger.info("draining worker");
|
|
267
|
+
this.#draining = true;
|
|
268
|
+
this.event.emit(
|
|
269
|
+
"worker_msg",
|
|
270
|
+
new WorkerMessage({
|
|
271
|
+
message: {
|
|
272
|
+
case: "updateWorker",
|
|
273
|
+
value: {
|
|
274
|
+
status: WorkerStatus.WS_FULL
|
|
275
|
+
}
|
|
254
276
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
})
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
277
|
+
})
|
|
278
|
+
);
|
|
279
|
+
const joinJobs = async () => {
|
|
280
|
+
return Promise.all(
|
|
281
|
+
this.#procPool.processes.map((proc) => {
|
|
282
|
+
if (!proc.runningJob) {
|
|
283
|
+
proc.close();
|
|
284
|
+
}
|
|
285
|
+
return proc.join();
|
|
286
|
+
})
|
|
287
|
+
);
|
|
288
|
+
};
|
|
289
|
+
const timer = setTimeout(() => {
|
|
290
|
+
throw new WorkerError("timed out draining");
|
|
291
|
+
}, timeout);
|
|
292
|
+
if (timeout === void 0) clearTimeout(timer);
|
|
293
|
+
await joinJobs().then(() => {
|
|
294
|
+
clearTimeout(timer);
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
async simulateJob(roomName, participantIdentity) {
|
|
298
|
+
const client = new RoomServiceClient(this.#opts.wsURL, this.#opts.apiKey, this.#opts.apiSecret);
|
|
299
|
+
const room = await client.createRoom({ name: roomName });
|
|
300
|
+
let participant = void 0;
|
|
301
|
+
if (participantIdentity) {
|
|
302
|
+
try {
|
|
303
|
+
participant = await client.getParticipant(roomName, participantIdentity);
|
|
304
|
+
} catch (e) {
|
|
305
|
+
this.#logger.fatal(
|
|
306
|
+
`participant with identity ${participantIdentity} not found in room ${roomName}`
|
|
307
|
+
);
|
|
308
|
+
throw e;
|
|
309
|
+
}
|
|
281
310
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
throw e;
|
|
293
|
-
}
|
|
311
|
+
this.event.emit(
|
|
312
|
+
"worker_msg",
|
|
313
|
+
new WorkerMessage({
|
|
314
|
+
message: {
|
|
315
|
+
case: "simulateJob",
|
|
316
|
+
value: {
|
|
317
|
+
type: JobType.JT_PUBLISHER,
|
|
318
|
+
room,
|
|
319
|
+
participant
|
|
320
|
+
}
|
|
294
321
|
}
|
|
295
|
-
|
|
322
|
+
})
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
#runWS(ws) {
|
|
326
|
+
let closingWS = false;
|
|
327
|
+
const send = (msg) => {
|
|
328
|
+
if (closingWS) {
|
|
329
|
+
this.event.off("worker_msg", send);
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
ws.send(msg.toBinary());
|
|
333
|
+
};
|
|
334
|
+
this.event.on("worker_msg", send);
|
|
335
|
+
ws.addEventListener("close", () => {
|
|
336
|
+
closingWS = true;
|
|
337
|
+
this.#logger.error("worker connection closed unexpectedly");
|
|
338
|
+
this.close();
|
|
339
|
+
});
|
|
340
|
+
ws.addEventListener("message", (event) => {
|
|
341
|
+
if (event.type !== "message") {
|
|
342
|
+
this.#logger.warn("unexpected message type: " + event.type);
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
const msg = new ServerMessage();
|
|
346
|
+
msg.fromBinary(event.data);
|
|
347
|
+
if (this.#connecting && msg.message.case !== "register") {
|
|
348
|
+
throw new WorkerError("expected register response as first message");
|
|
349
|
+
}
|
|
350
|
+
switch (msg.message.case) {
|
|
351
|
+
case "register": {
|
|
352
|
+
this.#id = msg.message.value.workerId;
|
|
353
|
+
this.#logger.child({ id: this.id, server_info: msg.message.value.serverInfo }).info("registered worker");
|
|
354
|
+
this.event.emit(
|
|
355
|
+
"worker_registered",
|
|
356
|
+
msg.message.value.workerId,
|
|
357
|
+
msg.message.value.serverInfo
|
|
358
|
+
);
|
|
359
|
+
this.#connecting = false;
|
|
360
|
+
break;
|
|
361
|
+
}
|
|
362
|
+
case "availability": {
|
|
363
|
+
if (!msg.message.value.job) return;
|
|
364
|
+
const task = this.#availability(msg.message.value);
|
|
365
|
+
this.#tasks.push(task);
|
|
366
|
+
task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));
|
|
367
|
+
break;
|
|
368
|
+
}
|
|
369
|
+
case "assignment": {
|
|
370
|
+
if (!msg.message.value.job) return;
|
|
371
|
+
const job = msg.message.value.job;
|
|
372
|
+
if (job.id in this.#pending) {
|
|
373
|
+
const task = this.#pending[job.id];
|
|
374
|
+
delete this.#pending[job.id];
|
|
375
|
+
task == null ? void 0 : task.resolve(msg.message.value);
|
|
376
|
+
} else {
|
|
377
|
+
this.#logger.child({ job }).warn("received assignment for unknown job " + job.id);
|
|
378
|
+
}
|
|
379
|
+
break;
|
|
380
|
+
}
|
|
381
|
+
case "termination": {
|
|
382
|
+
const task = this.#termination(msg.message.value);
|
|
383
|
+
this.#tasks.push(task);
|
|
384
|
+
task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
this.event.emit(
|
|
390
|
+
"worker_msg",
|
|
391
|
+
new WorkerMessage({
|
|
392
|
+
message: {
|
|
393
|
+
case: "register",
|
|
394
|
+
value: {
|
|
395
|
+
type: this.#opts.workerType,
|
|
396
|
+
agentName: this.#opts.agentName,
|
|
397
|
+
allowedPermissions: new ParticipantPermission({
|
|
398
|
+
canPublish: this.#opts.permissions.canPublish,
|
|
399
|
+
canSubscribe: this.#opts.permissions.canSubscribe,
|
|
400
|
+
canPublishData: this.#opts.permissions.canPublishData,
|
|
401
|
+
canUpdateMetadata: this.#opts.permissions.canUpdateMetadata,
|
|
402
|
+
hidden: this.#opts.permissions.hidden,
|
|
403
|
+
agent: true
|
|
404
|
+
}),
|
|
405
|
+
version
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
})
|
|
409
|
+
);
|
|
410
|
+
let currentStatus = WorkerStatus.WS_AVAILABLE;
|
|
411
|
+
const loadMonitor = setInterval(() => {
|
|
412
|
+
if (closingWS) clearInterval(loadMonitor);
|
|
413
|
+
const oldStatus = currentStatus;
|
|
414
|
+
this.#opts.loadFunc().then((currentLoad) => {
|
|
415
|
+
const isFull = currentLoad >= this.#opts.loadThreshold;
|
|
416
|
+
const currentlyAvailable = !isFull;
|
|
417
|
+
currentStatus = currentlyAvailable ? WorkerStatus.WS_AVAILABLE : WorkerStatus.WS_FULL;
|
|
418
|
+
if (oldStatus != currentStatus) {
|
|
419
|
+
const extra = { load: currentLoad, loadThreshold: this.#opts.loadThreshold };
|
|
420
|
+
if (isFull) {
|
|
421
|
+
this.#logger.child(extra).info("worker is at full capacity, marking as unavailable");
|
|
422
|
+
} else {
|
|
423
|
+
this.#logger.child(extra).info("worker is below capacity, marking as available");
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
this.event.emit(
|
|
427
|
+
"worker_msg",
|
|
428
|
+
new WorkerMessage({
|
|
296
429
|
message: {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
},
|
|
303
|
-
},
|
|
304
|
-
}));
|
|
305
|
-
}
|
|
306
|
-
#runWS(ws) {
|
|
307
|
-
let closingWS = false;
|
|
308
|
-
const send = (msg) => {
|
|
309
|
-
if (closingWS) {
|
|
310
|
-
this.event.off('worker_msg', send);
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
ws.send(msg.toBinary());
|
|
314
|
-
};
|
|
315
|
-
this.event.on('worker_msg', send);
|
|
316
|
-
ws.addEventListener('close', () => {
|
|
317
|
-
closingWS = true;
|
|
318
|
-
this.#logger.error('worker connection closed unexpectedly');
|
|
319
|
-
this.close();
|
|
320
|
-
});
|
|
321
|
-
ws.addEventListener('message', (event) => {
|
|
322
|
-
if (event.type !== 'message') {
|
|
323
|
-
this.#logger.warn('unexpected message type: ' + event.type);
|
|
324
|
-
return;
|
|
430
|
+
case: "updateWorker",
|
|
431
|
+
value: {
|
|
432
|
+
load: currentLoad,
|
|
433
|
+
status: currentStatus
|
|
434
|
+
}
|
|
325
435
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
436
|
+
})
|
|
437
|
+
);
|
|
438
|
+
});
|
|
439
|
+
}, UPDATE_LOAD_INTERVAL);
|
|
440
|
+
}
|
|
441
|
+
async #availability(msg) {
|
|
442
|
+
let answered = false;
|
|
443
|
+
const onReject = async () => {
|
|
444
|
+
answered = true;
|
|
445
|
+
this.event.emit(
|
|
446
|
+
"worker_msg",
|
|
447
|
+
new WorkerMessage({
|
|
448
|
+
message: {
|
|
449
|
+
case: "availability",
|
|
450
|
+
value: {
|
|
451
|
+
jobId: msg.job.id,
|
|
452
|
+
available: false
|
|
332
453
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
case 'assignment': {
|
|
352
|
-
if (!msg.message.value.job)
|
|
353
|
-
return;
|
|
354
|
-
const job = msg.message.value.job;
|
|
355
|
-
if (job.id in this.#pending) {
|
|
356
|
-
const task = this.#pending[job.id];
|
|
357
|
-
delete this.#pending[job.id];
|
|
358
|
-
task?.resolve(msg.message.value);
|
|
359
|
-
}
|
|
360
|
-
else {
|
|
361
|
-
this.#logger.child({ job }).warn('received assignment for unknown job ' + job.id);
|
|
362
|
-
}
|
|
363
|
-
break;
|
|
364
|
-
}
|
|
365
|
-
case 'termination': {
|
|
366
|
-
const task = this.#termination(msg.message.value);
|
|
367
|
-
this.#tasks.push(task);
|
|
368
|
-
task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));
|
|
369
|
-
break;
|
|
370
|
-
}
|
|
454
|
+
}
|
|
455
|
+
})
|
|
456
|
+
);
|
|
457
|
+
};
|
|
458
|
+
const onAccept = async (args) => {
|
|
459
|
+
var _a;
|
|
460
|
+
answered = true;
|
|
461
|
+
this.event.emit(
|
|
462
|
+
"worker_msg",
|
|
463
|
+
new WorkerMessage({
|
|
464
|
+
message: {
|
|
465
|
+
case: "availability",
|
|
466
|
+
value: {
|
|
467
|
+
jobId: msg.job.id,
|
|
468
|
+
available: true,
|
|
469
|
+
participantIdentity: args.identity,
|
|
470
|
+
participantName: args.name,
|
|
471
|
+
participantMetadata: args.metadata
|
|
371
472
|
}
|
|
473
|
+
}
|
|
474
|
+
})
|
|
475
|
+
);
|
|
476
|
+
this.#pending[req.id] = new PendingAssignment();
|
|
477
|
+
const timer = setTimeout(() => {
|
|
478
|
+
this.#logger.child({ req }).warn(`assignment for job ${req.id} timed out`);
|
|
479
|
+
return;
|
|
480
|
+
}, ASSIGNMENT_TIMEOUT);
|
|
481
|
+
const asgn = await ((_a = this.#pending[req.id]) == null ? void 0 : _a.promise.then(async (asgn2) => {
|
|
482
|
+
clearTimeout(timer);
|
|
483
|
+
return asgn2;
|
|
484
|
+
}));
|
|
485
|
+
if (asgn) {
|
|
486
|
+
await this.#procPool.launchJob({
|
|
487
|
+
acceptArguments: args,
|
|
488
|
+
job: msg.job,
|
|
489
|
+
url: asgn.url || this.#opts.wsURL,
|
|
490
|
+
token: asgn.token
|
|
372
491
|
});
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
const currentlyAvailable = !isFull;
|
|
399
|
-
currentStatus = currentlyAvailable ? WorkerStatus.WS_AVAILABLE : WorkerStatus.WS_FULL;
|
|
400
|
-
if (oldStatus != currentStatus) {
|
|
401
|
-
const extra = { load: currentLoad, loadThreshold: this.#opts.loadThreshold };
|
|
402
|
-
if (isFull) {
|
|
403
|
-
this.#logger.child(extra).info('worker is at full capacity, marking as unavailable');
|
|
404
|
-
}
|
|
405
|
-
else {
|
|
406
|
-
this.#logger.child(extra).info('worker is below capacity, marking as available');
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
this.event.emit('worker_msg', new WorkerMessage({
|
|
410
|
-
message: {
|
|
411
|
-
case: 'updateWorker',
|
|
412
|
-
value: {
|
|
413
|
-
load: currentLoad,
|
|
414
|
-
status: currentStatus,
|
|
415
|
-
},
|
|
416
|
-
},
|
|
417
|
-
}));
|
|
418
|
-
});
|
|
419
|
-
}, UPDATE_LOAD_INTERVAL);
|
|
492
|
+
} else {
|
|
493
|
+
this.#logger.child({ requestId: req.id }).warn("pending assignment not found");
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
const req = new JobRequest(msg.job, onReject, onAccept);
|
|
497
|
+
this.#logger.child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName }).info("received job request");
|
|
498
|
+
const jobRequestTask = async () => {
|
|
499
|
+
try {
|
|
500
|
+
await this.#opts.requestFunc(req);
|
|
501
|
+
} catch (e) {
|
|
502
|
+
this.#logger.child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName }).info("jobRequestFunc failed");
|
|
503
|
+
await onReject();
|
|
504
|
+
}
|
|
505
|
+
if (!answered) {
|
|
506
|
+
this.#logger.child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName }).info("no answer was given inside the jobRequestFunc, automatically rejecting the job");
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
const task = jobRequestTask();
|
|
510
|
+
this.#tasks.push(task);
|
|
511
|
+
task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));
|
|
512
|
+
}
|
|
513
|
+
async #termination(msg) {
|
|
514
|
+
const proc = this.#procPool.getByJobId(msg.jobId);
|
|
515
|
+
if (proc === null) {
|
|
516
|
+
return;
|
|
420
517
|
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
value: {
|
|
429
|
-
jobId: msg.job.id,
|
|
430
|
-
available: false,
|
|
431
|
-
},
|
|
432
|
-
},
|
|
433
|
-
}));
|
|
434
|
-
};
|
|
435
|
-
const onAccept = async (args) => {
|
|
436
|
-
answered = true;
|
|
437
|
-
this.event.emit('worker_msg', new WorkerMessage({
|
|
438
|
-
message: {
|
|
439
|
-
case: 'availability',
|
|
440
|
-
value: {
|
|
441
|
-
jobId: msg.job.id,
|
|
442
|
-
available: true,
|
|
443
|
-
participantIdentity: args.identity,
|
|
444
|
-
participantName: args.name,
|
|
445
|
-
participantMetadata: args.metadata,
|
|
446
|
-
},
|
|
447
|
-
},
|
|
448
|
-
}));
|
|
449
|
-
this.#pending[req.id] = new PendingAssignment();
|
|
450
|
-
const timer = setTimeout(() => {
|
|
451
|
-
this.#logger.child({ req }).warn(`assignment for job ${req.id} timed out`);
|
|
452
|
-
return;
|
|
453
|
-
}, ASSIGNMENT_TIMEOUT);
|
|
454
|
-
const asgn = await this.#pending[req.id]?.promise.then(async (asgn) => {
|
|
455
|
-
clearTimeout(timer);
|
|
456
|
-
return asgn;
|
|
457
|
-
});
|
|
458
|
-
if (asgn) {
|
|
459
|
-
await this.#procPool.launchJob({
|
|
460
|
-
acceptArguments: args,
|
|
461
|
-
job: msg.job,
|
|
462
|
-
url: asgn.url || this.#opts.wsURL,
|
|
463
|
-
token: asgn.token,
|
|
464
|
-
});
|
|
465
|
-
}
|
|
466
|
-
else {
|
|
467
|
-
this.#logger.child({ requestId: req.id }).warn('pending assignment not found');
|
|
468
|
-
}
|
|
469
|
-
};
|
|
470
|
-
const req = new JobRequest(msg.job, onReject, onAccept);
|
|
471
|
-
this.#logger
|
|
472
|
-
.child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName })
|
|
473
|
-
.info('received job request');
|
|
474
|
-
const jobRequestTask = async () => {
|
|
475
|
-
try {
|
|
476
|
-
await this.#opts.requestFunc(req);
|
|
477
|
-
}
|
|
478
|
-
catch (e) {
|
|
479
|
-
this.#logger
|
|
480
|
-
.child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName })
|
|
481
|
-
.info('jobRequestFunc failed');
|
|
482
|
-
await onReject();
|
|
483
|
-
}
|
|
484
|
-
if (!answered) {
|
|
485
|
-
this.#logger
|
|
486
|
-
.child({ job: msg.job, resuming: msg.resuming, agentName: this.#opts.agentName })
|
|
487
|
-
.info('no answer was given inside the jobRequestFunc, automatically rejecting the job');
|
|
488
|
-
}
|
|
489
|
-
};
|
|
490
|
-
const task = jobRequestTask();
|
|
491
|
-
this.#tasks.push(task);
|
|
492
|
-
task.finally(() => this.#tasks.splice(this.#tasks.indexOf(task)));
|
|
493
|
-
}
|
|
494
|
-
async #termination(msg) {
|
|
495
|
-
const proc = this.#procPool.getByJobId(msg.jobId);
|
|
496
|
-
if (proc === null) {
|
|
497
|
-
// safe to ignore
|
|
498
|
-
return;
|
|
499
|
-
}
|
|
500
|
-
await proc.close();
|
|
501
|
-
}
|
|
502
|
-
async close() {
|
|
503
|
-
if (this.#closed) {
|
|
504
|
-
await this.#close.await;
|
|
505
|
-
return;
|
|
506
|
-
}
|
|
507
|
-
this.#logger.info('shutting down worker');
|
|
508
|
-
this.#closed = true;
|
|
509
|
-
await this.#procPool.close();
|
|
510
|
-
await this.#httpServer.close();
|
|
511
|
-
await Promise.allSettled(this.#tasks);
|
|
512
|
-
this.#session?.close();
|
|
513
|
-
await this.#close.await;
|
|
518
|
+
await proc.close();
|
|
519
|
+
}
|
|
520
|
+
async close() {
|
|
521
|
+
var _a;
|
|
522
|
+
if (this.#closed) {
|
|
523
|
+
await this.#close.await;
|
|
524
|
+
return;
|
|
514
525
|
}
|
|
526
|
+
this.#logger.info("shutting down worker");
|
|
527
|
+
this.#closed = true;
|
|
528
|
+
await this.#procPool.close();
|
|
529
|
+
await this.#httpServer.close();
|
|
530
|
+
await Promise.allSettled(this.#tasks);
|
|
531
|
+
(_a = this.#session) == null ? void 0 : _a.close();
|
|
532
|
+
await this.#close.await;
|
|
533
|
+
}
|
|
515
534
|
}
|
|
535
|
+
export {
|
|
536
|
+
MissingCredentialsError,
|
|
537
|
+
Worker,
|
|
538
|
+
WorkerError,
|
|
539
|
+
WorkerOptions,
|
|
540
|
+
WorkerPermissions,
|
|
541
|
+
defaultInitializeProcessFunc
|
|
542
|
+
};
|
|
516
543
|
//# sourceMappingURL=worker.js.map
|