@taskcast/core 0.2.0 → 0.3.1
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/config.d.ts +13 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/engine.d.ts +17 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +93 -5
- package/dist/engine.js.map +1 -1
- package/dist/heartbeat-monitor.d.ts +40 -0
- package/dist/heartbeat-monitor.d.ts.map +1 -0
- package/dist/heartbeat-monitor.js +139 -0
- package/dist/heartbeat-monitor.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/memory-adapters.d.ts +15 -1
- package/dist/memory-adapters.d.ts.map +1 -1
- package/dist/memory-adapters.js +93 -0
- package/dist/memory-adapters.js.map +1 -1
- package/dist/scheduler.d.ts +24 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +64 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/series.d.ts.map +1 -1
- package/dist/series.js +3 -2
- package/dist/series.js.map +1 -1
- package/dist/state-machine.d.ts.map +1 -1
- package/dist/state-machine.js +4 -3
- package/dist/state-machine.js.map +1 -1
- package/dist/types.d.ts +87 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/worker-manager.d.ts +68 -0
- package/dist/worker-manager.d.ts.map +1 -0
- package/dist/worker-manager.js +336 -0
- package/dist/worker-manager.js.map +1 -0
- package/dist/worker-matching.d.ts +23 -0
- package/dist/worker-matching.d.ts.map +1 -0
- package/dist/worker-matching.js +50 -0
- package/dist/worker-matching.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import { ulid } from 'ulidx';
|
|
2
|
+
import { matchesWorkerRule } from './worker-matching.js';
|
|
3
|
+
// ─── WorkerManager ──────────────────────────────────────────────────────────
|
|
4
|
+
export class WorkerManager {
|
|
5
|
+
opts;
|
|
6
|
+
engine;
|
|
7
|
+
shortTermStore;
|
|
8
|
+
longTermStore;
|
|
9
|
+
hooks;
|
|
10
|
+
constructor(opts) {
|
|
11
|
+
this.opts = opts;
|
|
12
|
+
this.engine = opts.engine;
|
|
13
|
+
this.shortTermStore = opts.shortTermStore;
|
|
14
|
+
if (opts.longTermStore)
|
|
15
|
+
this.longTermStore = opts.longTermStore;
|
|
16
|
+
if (opts.hooks)
|
|
17
|
+
this.hooks = opts.hooks;
|
|
18
|
+
}
|
|
19
|
+
get heartbeatIntervalMs() {
|
|
20
|
+
return this.opts.defaults?.heartbeatIntervalMs ?? 30_000;
|
|
21
|
+
}
|
|
22
|
+
// ─── Audit Helpers ──────────────────────────────────────────────────────
|
|
23
|
+
async emitTaskAudit(taskId, action, extra) {
|
|
24
|
+
try {
|
|
25
|
+
await this.opts.engine.publishEvent(taskId, {
|
|
26
|
+
type: 'taskcast:audit',
|
|
27
|
+
level: 'info',
|
|
28
|
+
data: { action, ...extra },
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// Task may be in terminal state or not found; audit is best-effort
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
emitWorkerAudit(action, workerId, data) {
|
|
36
|
+
if (!this.opts.longTermStore)
|
|
37
|
+
return;
|
|
38
|
+
const event = {
|
|
39
|
+
id: ulid(),
|
|
40
|
+
workerId,
|
|
41
|
+
timestamp: Date.now(),
|
|
42
|
+
action,
|
|
43
|
+
...(data !== undefined && { data }),
|
|
44
|
+
};
|
|
45
|
+
this.opts.longTermStore.saveWorkerEvent(event).catch(() => { });
|
|
46
|
+
}
|
|
47
|
+
// ─── Worker Registration & Lifecycle ────────────────────────────────────
|
|
48
|
+
async registerWorker(config) {
|
|
49
|
+
const now = Date.now();
|
|
50
|
+
const worker = {
|
|
51
|
+
id: config.id ?? ulid(),
|
|
52
|
+
status: 'idle',
|
|
53
|
+
matchRule: config.matchRule,
|
|
54
|
+
capacity: config.capacity,
|
|
55
|
+
usedSlots: 0,
|
|
56
|
+
weight: config.weight ?? 50,
|
|
57
|
+
connectionMode: config.connectionMode,
|
|
58
|
+
connectedAt: now,
|
|
59
|
+
lastHeartbeatAt: now,
|
|
60
|
+
...(config.metadata !== undefined && { metadata: config.metadata }),
|
|
61
|
+
};
|
|
62
|
+
await this.shortTermStore.saveWorker(worker);
|
|
63
|
+
this.emitWorkerAudit('connected', worker.id);
|
|
64
|
+
this.hooks?.onWorkerConnected?.(worker);
|
|
65
|
+
return worker;
|
|
66
|
+
}
|
|
67
|
+
async unregisterWorker(workerId) {
|
|
68
|
+
const worker = await this.shortTermStore.getWorker(workerId);
|
|
69
|
+
await this.shortTermStore.deleteWorker(workerId);
|
|
70
|
+
if (worker) {
|
|
71
|
+
this.emitWorkerAudit('disconnected', workerId, { reason: 'unregistered' });
|
|
72
|
+
this.hooks?.onWorkerDisconnected?.(worker, 'unregistered');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async updateWorker(workerId, update) {
|
|
76
|
+
const worker = await this.shortTermStore.getWorker(workerId);
|
|
77
|
+
if (!worker)
|
|
78
|
+
return null;
|
|
79
|
+
if (update.weight !== undefined)
|
|
80
|
+
worker.weight = update.weight;
|
|
81
|
+
if (update.capacity !== undefined)
|
|
82
|
+
worker.capacity = update.capacity;
|
|
83
|
+
if (update.matchRule !== undefined)
|
|
84
|
+
worker.matchRule = update.matchRule;
|
|
85
|
+
if (update.status !== undefined)
|
|
86
|
+
worker.status = update.status;
|
|
87
|
+
await this.shortTermStore.saveWorker(worker);
|
|
88
|
+
return worker;
|
|
89
|
+
}
|
|
90
|
+
async heartbeat(workerId) {
|
|
91
|
+
const worker = await this.shortTermStore.getWorker(workerId);
|
|
92
|
+
if (!worker)
|
|
93
|
+
return;
|
|
94
|
+
worker.lastHeartbeatAt = Date.now();
|
|
95
|
+
await this.shortTermStore.saveWorker(worker);
|
|
96
|
+
}
|
|
97
|
+
async getWorker(workerId) {
|
|
98
|
+
return this.shortTermStore.getWorker(workerId);
|
|
99
|
+
}
|
|
100
|
+
async listWorkers(filter) {
|
|
101
|
+
return this.shortTermStore.listWorkers(filter);
|
|
102
|
+
}
|
|
103
|
+
// ─── Task Dispatch ─────────────────────────────────────────────────────
|
|
104
|
+
async dispatchTask(taskId) {
|
|
105
|
+
const task = await this.engine.getTask(taskId);
|
|
106
|
+
if (!task || task.status !== 'pending') {
|
|
107
|
+
return { matched: false };
|
|
108
|
+
}
|
|
109
|
+
const blacklist = task.metadata?._blacklistedWorkers ?? [];
|
|
110
|
+
const workers = await this.shortTermStore.listWorkers({ status: ['idle', 'busy'] });
|
|
111
|
+
const taskCost = task.cost ?? 1;
|
|
112
|
+
const candidates = workers.filter((w) => {
|
|
113
|
+
if (blacklist.includes(w.id))
|
|
114
|
+
return false;
|
|
115
|
+
if (w.usedSlots + taskCost > w.capacity)
|
|
116
|
+
return false;
|
|
117
|
+
if (!matchesWorkerRule(task, w.matchRule))
|
|
118
|
+
return false;
|
|
119
|
+
return true;
|
|
120
|
+
});
|
|
121
|
+
if (candidates.length === 0) {
|
|
122
|
+
return { matched: false };
|
|
123
|
+
}
|
|
124
|
+
// Sort: weight desc → available slots desc → connectedAt asc
|
|
125
|
+
candidates.sort((a, b) => {
|
|
126
|
+
if (b.weight !== a.weight)
|
|
127
|
+
return b.weight - a.weight;
|
|
128
|
+
const aAvailable = a.capacity - a.usedSlots;
|
|
129
|
+
const bAvailable = b.capacity - b.usedSlots;
|
|
130
|
+
if (bAvailable !== aAvailable)
|
|
131
|
+
return bAvailable - aAvailable;
|
|
132
|
+
return a.connectedAt - b.connectedAt;
|
|
133
|
+
});
|
|
134
|
+
return { matched: true, workerId: candidates[0].id };
|
|
135
|
+
}
|
|
136
|
+
// ─── Task Claim ────────────────────────────────────────────────────────
|
|
137
|
+
async claimTask(taskId, workerId) {
|
|
138
|
+
const task = await this.engine.getTask(taskId);
|
|
139
|
+
if (!task) {
|
|
140
|
+
return { success: false, reason: 'Task not found' };
|
|
141
|
+
}
|
|
142
|
+
if (task.status !== 'pending') {
|
|
143
|
+
return { success: false, reason: `Task is not pending (status: ${task.status})` };
|
|
144
|
+
}
|
|
145
|
+
const cost = task.cost ?? 1;
|
|
146
|
+
const claimed = await this.shortTermStore.claimTask(taskId, workerId, cost);
|
|
147
|
+
if (!claimed) {
|
|
148
|
+
return { success: false, reason: 'Claim failed (concurrent modification)' };
|
|
149
|
+
}
|
|
150
|
+
// claimTask atomically sets status to 'assigned' and assignedWorker on the
|
|
151
|
+
// store. Re-read to get the authoritative state, then persist to longTermStore.
|
|
152
|
+
const updatedTask = (await this.shortTermStore.getTask(taskId));
|
|
153
|
+
if (this.longTermStore)
|
|
154
|
+
await this.longTermStore.saveTask(updatedTask);
|
|
155
|
+
// Emit audit events for the claim
|
|
156
|
+
this.emitWorkerAudit('task_assigned', workerId, { taskId });
|
|
157
|
+
await this.emitTaskAudit(taskId, 'assigned', { workerId });
|
|
158
|
+
// Create assignment record
|
|
159
|
+
const assignment = {
|
|
160
|
+
taskId,
|
|
161
|
+
workerId,
|
|
162
|
+
cost,
|
|
163
|
+
assignedAt: Date.now(),
|
|
164
|
+
status: 'assigned',
|
|
165
|
+
};
|
|
166
|
+
await this.shortTermStore.addAssignment(assignment);
|
|
167
|
+
// Update worker status (usedSlots already updated by claimTask)
|
|
168
|
+
const worker = await this.shortTermStore.getWorker(workerId);
|
|
169
|
+
if (worker) {
|
|
170
|
+
worker.status = worker.usedSlots >= worker.capacity ? 'busy' : 'idle';
|
|
171
|
+
await this.shortTermStore.saveWorker(worker);
|
|
172
|
+
this.hooks?.onTaskAssigned?.(updatedTask, worker);
|
|
173
|
+
}
|
|
174
|
+
return { success: true };
|
|
175
|
+
}
|
|
176
|
+
// ─── Task Decline ──────────────────────────────────────────────────────
|
|
177
|
+
async declineTask(taskId, workerId, opts) {
|
|
178
|
+
const assignment = await this.shortTermStore.getTaskAssignment(taskId);
|
|
179
|
+
if (!assignment || assignment.workerId !== workerId)
|
|
180
|
+
return;
|
|
181
|
+
// Remove assignment
|
|
182
|
+
await this.shortTermStore.removeAssignment(taskId);
|
|
183
|
+
// Restore worker capacity
|
|
184
|
+
const worker = await this.shortTermStore.getWorker(workerId);
|
|
185
|
+
if (worker) {
|
|
186
|
+
worker.usedSlots = Math.max(0, worker.usedSlots - assignment.cost);
|
|
187
|
+
worker.status = 'idle';
|
|
188
|
+
await this.shortTermStore.saveWorker(worker);
|
|
189
|
+
}
|
|
190
|
+
// Transition task back to pending
|
|
191
|
+
await this.engine.transitionTask(taskId, 'pending');
|
|
192
|
+
// Emit audit events for the decline
|
|
193
|
+
const blacklisted = opts?.blacklist ?? false;
|
|
194
|
+
this.emitWorkerAudit('task_declined', workerId, { taskId });
|
|
195
|
+
await this.emitTaskAudit(taskId, 'declined', { workerId, blacklisted });
|
|
196
|
+
// Clear assignedWorker
|
|
197
|
+
const task = await this.engine.getTask(taskId);
|
|
198
|
+
if (task) {
|
|
199
|
+
delete task.assignedWorker;
|
|
200
|
+
// Add to blacklist if requested
|
|
201
|
+
if (opts?.blacklist) {
|
|
202
|
+
const metadata = task.metadata ?? {};
|
|
203
|
+
const existing = metadata._blacklistedWorkers ?? [];
|
|
204
|
+
metadata._blacklistedWorkers = [...existing, workerId];
|
|
205
|
+
task.metadata = metadata;
|
|
206
|
+
}
|
|
207
|
+
await this.shortTermStore.saveTask(task);
|
|
208
|
+
if (this.longTermStore)
|
|
209
|
+
await this.longTermStore.saveTask(task);
|
|
210
|
+
if (worker) {
|
|
211
|
+
this.hooks?.onTaskDeclined?.(task, worker, blacklisted);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// ─── Worker Tasks ──────────────────────────────────────────────────────
|
|
216
|
+
async getWorkerTasks(workerId) {
|
|
217
|
+
return this.shortTermStore.getWorkerAssignments(workerId);
|
|
218
|
+
}
|
|
219
|
+
// ─── Task Release ───────────────────────────────────────────────────────
|
|
220
|
+
async releaseTask(taskId) {
|
|
221
|
+
const assignment = await this.shortTermStore.getTaskAssignment(taskId);
|
|
222
|
+
if (!assignment)
|
|
223
|
+
return;
|
|
224
|
+
// Remove the assignment record
|
|
225
|
+
await this.shortTermStore.removeAssignment(taskId);
|
|
226
|
+
// Restore worker capacity (but don't change status if offline/draining)
|
|
227
|
+
const worker = await this.shortTermStore.getWorker(assignment.workerId);
|
|
228
|
+
if (worker) {
|
|
229
|
+
worker.usedSlots = Math.max(0, worker.usedSlots - assignment.cost);
|
|
230
|
+
if (worker.status !== 'offline' && worker.status !== 'draining') {
|
|
231
|
+
worker.status = worker.usedSlots >= worker.capacity ? 'busy' : 'idle';
|
|
232
|
+
}
|
|
233
|
+
await this.shortTermStore.saveWorker(worker);
|
|
234
|
+
}
|
|
235
|
+
// Clear assignedWorker on the task
|
|
236
|
+
const task = await this.engine.getTask(taskId);
|
|
237
|
+
if (task) {
|
|
238
|
+
delete task.assignedWorker;
|
|
239
|
+
await this.shortTermStore.saveTask(task);
|
|
240
|
+
}
|
|
241
|
+
this.emitWorkerAudit('task_reclaimed', assignment.workerId, { taskId });
|
|
242
|
+
}
|
|
243
|
+
// ─── Pull Mode (Long-Poll) ─────────────────────────────────────────────
|
|
244
|
+
async waitForTask(workerId, signal) {
|
|
245
|
+
const worker = await this.shortTermStore.getWorker(workerId);
|
|
246
|
+
if (!worker)
|
|
247
|
+
throw new Error(`Worker not found: ${workerId}`);
|
|
248
|
+
// Check if already aborted
|
|
249
|
+
if (signal?.aborted) {
|
|
250
|
+
throw new Error('aborted');
|
|
251
|
+
}
|
|
252
|
+
// Check existing pending pull tasks
|
|
253
|
+
const pendingTasks = await this.shortTermStore.listTasks({ status: ['pending'], assignMode: ['pull'] });
|
|
254
|
+
const blacklist = new Set();
|
|
255
|
+
for (const task of pendingTasks) {
|
|
256
|
+
const taskBlacklist = task.metadata?._blacklistedWorkers ?? [];
|
|
257
|
+
if (taskBlacklist.includes(workerId))
|
|
258
|
+
continue;
|
|
259
|
+
if (!matchesWorkerRule(task, worker.matchRule))
|
|
260
|
+
continue;
|
|
261
|
+
const taskCost = task.cost ?? 1;
|
|
262
|
+
if (worker.usedSlots + taskCost > worker.capacity)
|
|
263
|
+
continue;
|
|
264
|
+
const result = await this.claimTask(task.id, workerId);
|
|
265
|
+
if (result.success) {
|
|
266
|
+
this.emitWorkerAudit('pull_request', workerId, { matched: true, taskId: task.id });
|
|
267
|
+
const claimed = await this.engine.getTask(task.id);
|
|
268
|
+
return claimed;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
// Wait for a new task notification via broadcast
|
|
272
|
+
return new Promise((resolve, reject) => {
|
|
273
|
+
let unsubscribe;
|
|
274
|
+
const cleanup = () => {
|
|
275
|
+
unsubscribe?.();
|
|
276
|
+
signal?.removeEventListener('abort', onAbort);
|
|
277
|
+
};
|
|
278
|
+
const onAbort = () => {
|
|
279
|
+
cleanup();
|
|
280
|
+
this.emitWorkerAudit('pull_request', workerId, { matched: false });
|
|
281
|
+
reject(new Error('aborted'));
|
|
282
|
+
};
|
|
283
|
+
if (signal) {
|
|
284
|
+
signal.addEventListener('abort', onAbort);
|
|
285
|
+
}
|
|
286
|
+
unsubscribe = this.opts.broadcast.subscribe('taskcast:worker:new-task', async (event) => {
|
|
287
|
+
const taskId = event.data;
|
|
288
|
+
try {
|
|
289
|
+
// Re-fetch the worker to get current state
|
|
290
|
+
const currentWorker = await this.shortTermStore.getWorker(workerId);
|
|
291
|
+
if (!currentWorker) {
|
|
292
|
+
cleanup();
|
|
293
|
+
reject(new Error(`Worker not found: ${workerId}`));
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
const task = await this.engine.getTask(taskId);
|
|
297
|
+
if (!task || task.status !== 'pending')
|
|
298
|
+
return;
|
|
299
|
+
if (task.assignMode !== 'pull')
|
|
300
|
+
return;
|
|
301
|
+
const taskBlacklist = task.metadata?._blacklistedWorkers ?? [];
|
|
302
|
+
if (taskBlacklist.includes(workerId))
|
|
303
|
+
return;
|
|
304
|
+
if (!matchesWorkerRule(task, currentWorker.matchRule))
|
|
305
|
+
return;
|
|
306
|
+
const taskCost = task.cost ?? 1;
|
|
307
|
+
if (currentWorker.usedSlots + taskCost > currentWorker.capacity)
|
|
308
|
+
return;
|
|
309
|
+
const result = await this.claimTask(taskId, workerId);
|
|
310
|
+
if (result.success) {
|
|
311
|
+
cleanup();
|
|
312
|
+
this.emitWorkerAudit('pull_request', workerId, { matched: true, taskId });
|
|
313
|
+
const claimed = await this.engine.getTask(taskId);
|
|
314
|
+
resolve(claimed);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
catch {
|
|
318
|
+
// Ignore errors from individual task checks
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
async notifyNewTask(taskId) {
|
|
324
|
+
const event = {
|
|
325
|
+
id: ulid(),
|
|
326
|
+
taskId: 'system',
|
|
327
|
+
index: 0,
|
|
328
|
+
timestamp: Date.now(),
|
|
329
|
+
type: 'taskcast:worker:new-task',
|
|
330
|
+
level: 'info',
|
|
331
|
+
data: taskId,
|
|
332
|
+
};
|
|
333
|
+
await this.opts.broadcast.publish('taskcast:worker:new-task', event);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
//# sourceMappingURL=worker-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-manager.js","sourceRoot":"","sources":["../src/worker-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Task, TagMatcher, WorkerMatchRule } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Checks if a set of task tags matches a TagMatcher.
|
|
4
|
+
*
|
|
5
|
+
* - `all`: every tag in `all` must exist in taskTags
|
|
6
|
+
* - `any`: at least one tag in `any` must exist in taskTags
|
|
7
|
+
* - `none`: none of the tags in `none` may exist in taskTags
|
|
8
|
+
* - Empty/undefined matcher matches everything
|
|
9
|
+
* - Undefined taskTags treated as empty array
|
|
10
|
+
* - Empty arrays in matcher fields are vacuous true
|
|
11
|
+
*/
|
|
12
|
+
export declare function matchesTag(taskTags: string[] | undefined, matcher: TagMatcher): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Checks if a task matches a WorkerMatchRule.
|
|
15
|
+
*
|
|
16
|
+
* - If rule has `taskTypes`: task.type must match using wildcard matching
|
|
17
|
+
* - If rule has `tags`: use matchesTag
|
|
18
|
+
* - Both conditions are AND'd
|
|
19
|
+
* - Empty/no rule matches everything
|
|
20
|
+
* - Task with no `type` does not match if rule has `taskTypes`
|
|
21
|
+
*/
|
|
22
|
+
export declare function matchesWorkerRule(task: Task, rule: WorkerMatchRule): boolean;
|
|
23
|
+
//# sourceMappingURL=worker-matching.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-matching.d.ts","sourceRoot":"","sources":["../src/worker-matching.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAGnE;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAgBvF;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAW5E"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { matchesType } from './filter.js';
|
|
2
|
+
/**
|
|
3
|
+
* Checks if a set of task tags matches a TagMatcher.
|
|
4
|
+
*
|
|
5
|
+
* - `all`: every tag in `all` must exist in taskTags
|
|
6
|
+
* - `any`: at least one tag in `any` must exist in taskTags
|
|
7
|
+
* - `none`: none of the tags in `none` may exist in taskTags
|
|
8
|
+
* - Empty/undefined matcher matches everything
|
|
9
|
+
* - Undefined taskTags treated as empty array
|
|
10
|
+
* - Empty arrays in matcher fields are vacuous true
|
|
11
|
+
*/
|
|
12
|
+
export function matchesTag(taskTags, matcher) {
|
|
13
|
+
const tags = taskTags ?? [];
|
|
14
|
+
if (matcher.all !== undefined && matcher.all.length > 0) {
|
|
15
|
+
if (!matcher.all.every((tag) => tags.includes(tag)))
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
if (matcher.any !== undefined && matcher.any.length > 0) {
|
|
19
|
+
if (!matcher.any.some((tag) => tags.includes(tag)))
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
if (matcher.none !== undefined && matcher.none.length > 0) {
|
|
23
|
+
if (matcher.none.some((tag) => tags.includes(tag)))
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Checks if a task matches a WorkerMatchRule.
|
|
30
|
+
*
|
|
31
|
+
* - If rule has `taskTypes`: task.type must match using wildcard matching
|
|
32
|
+
* - If rule has `tags`: use matchesTag
|
|
33
|
+
* - Both conditions are AND'd
|
|
34
|
+
* - Empty/no rule matches everything
|
|
35
|
+
* - Task with no `type` does not match if rule has `taskTypes`
|
|
36
|
+
*/
|
|
37
|
+
export function matchesWorkerRule(task, rule) {
|
|
38
|
+
if (rule.taskTypes !== undefined && rule.taskTypes.length > 0) {
|
|
39
|
+
if (task.type === undefined)
|
|
40
|
+
return false;
|
|
41
|
+
if (!matchesType(task.type, rule.taskTypes))
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
if (rule.tags !== undefined) {
|
|
45
|
+
if (!matchesTag(task.tags, rule.tags))
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=worker-matching.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-matching.js","sourceRoot":"","sources":["../src/worker-matching.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEzC;;;;;;;;;GASG;AACH,MAAM,UAAU,UAAU,CAAC,QAA8B,EAAE,OAAmB;IAC5E,MAAM,IAAI,GAAG,QAAQ,IAAI,EAAE,CAAA;IAE3B,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YAAE,OAAO,KAAK,CAAA;IACnE,CAAC;IAED,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YAAE,OAAO,KAAK,CAAA;IAClE,CAAC;IAED,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1D,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YAAE,OAAO,KAAK,CAAA;IAClE,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAU,EAAE,IAAqB;IACjE,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9D,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;YAAE,OAAO,KAAK,CAAA;QACzC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YAAE,OAAO,KAAK,CAAA;IAC3D,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC5B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAA;IACrD,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC"}
|