0
# Task Queues
1
2
Configurable task scheduling systems that control how method calls are distributed and prioritized across workers. Jest Worker supports pluggable queue implementations to optimize task execution based on different strategies.
3
4
## Capabilities
5
6
### Task Queue Interface
7
8
Base interface for implementing custom task scheduling strategies.
9
10
```typescript { .api }
11
/**
12
* Interface for task queue implementations that manage task distribution
13
*/
14
interface TaskQueue {
15
/**
16
* Enqueue a task for execution by a specific worker or shared queue
17
* @param task - The task to be queued
18
* @param workerId - Optional worker ID for worker-specific tasks
19
*/
20
enqueue(task: QueueChildMessage, workerId?: number): void;
21
22
/**
23
* Dequeue the next task for a specific worker
24
* @param workerId - ID of the worker requesting a task
25
* @returns Next task for the worker or null if none available
26
*/
27
dequeue(workerId: number): QueueChildMessage | null;
28
}
29
30
interface QueueChildMessage {
31
request: ChildMessageCall;
32
onStart: OnStart;
33
onEnd: OnEnd;
34
onCustomMessage: OnCustomMessage;
35
}
36
```
37
38
### FIFO Queue
39
40
First-in, first-out task queue that maintains strict ordering across worker-specific and shared queues. This is the default queue implementation.
41
42
```typescript { .api }
43
/**
44
* First-in, first-out task queue with cross-queue ordering guarantees
45
* Maintains FIFO ordering between worker-specific and shared queues
46
*/
47
class FifoQueue implements TaskQueue {
48
/** Add task to worker-specific or shared queue */
49
enqueue(task: QueueChildMessage, workerId?: number): void;
50
51
/** Get next task for worker, respecting FIFO ordering */
52
dequeue(workerId: number): QueueChildMessage | null;
53
}
54
```
55
56
**Usage Examples:**
57
58
```typescript
59
import { Worker, FifoQueue } from "jest-worker";
60
61
// Default FIFO behavior (no need to specify)
62
const worker = new Worker("./worker.js");
63
64
// Explicitly using FIFO queue
65
const fifoWorker = new Worker("./worker.js", {
66
taskQueue: new FifoQueue()
67
});
68
69
// Tasks are processed in strict order
70
await worker.task1(); // Executed first
71
await worker.task2(); // Executed second
72
await worker.task3(); // Executed third
73
```
74
75
### Priority Queue
76
77
Priority-based task queue that processes tasks according to computed priority values. Lower priority numbers are processed first.
78
79
```typescript { .api }
80
/**
81
* Priority queue that processes tasks by computed priority (lower first)
82
* FIFO ordering is not guaranteed for tasks with the same priority
83
* Worker-specific tasks with same priority as shared tasks are processed first
84
*/
85
class PriorityQueue implements TaskQueue {
86
/**
87
* Create priority queue with custom priority computation
88
* @param computePriority - Function to compute task priority
89
*/
90
constructor(computePriority: ComputeTaskPriorityCallback);
91
92
/** Add task to appropriate priority queue */
93
enqueue(task: QueueChildMessage, workerId?: number): void;
94
95
/** Get highest priority task for worker */
96
dequeue(workerId: number): QueueChildMessage | null;
97
}
98
99
/**
100
* Function to compute priority for tasks
101
* @param method - Name of the method being called
102
* @param args - Arguments passed to the method
103
* @returns Priority number (lower values = higher priority)
104
*/
105
type ComputeTaskPriorityCallback = (
106
method: string,
107
...args: Array<unknown>
108
) => number;
109
```
110
111
**Usage Examples:**
112
113
```typescript
114
import { Worker, PriorityQueue } from "jest-worker";
115
116
// Priority by file size (smaller files first)
117
const fileSizeQueue = new PriorityQueue((method, filepath) => {
118
if (method === "processFile") {
119
const stats = fs.statSync(filepath);
120
return stats.size; // Smaller files = lower priority number = higher priority
121
}
122
return 0; // Default priority for other methods
123
});
124
125
const worker = new Worker("./file-processor.js", {
126
taskQueue: fileSizeQueue
127
});
128
129
// Priority by method importance
130
const methodPriorityQueue = new PriorityQueue((method) => {
131
const priorities = {
132
criticalTask: 1, // Highest priority
133
normalTask: 5, // Medium priority
134
backgroundTask: 10 // Lowest priority
135
};
136
return priorities[method] || 5;
137
});
138
139
const priorityWorker = new Worker("./multi-task-worker.js", {
140
taskQueue: methodPriorityQueue
141
});
142
143
// These will be executed in priority order, not call order
144
await priorityWorker.backgroundTask(); // Priority 10 - executed last
145
await priorityWorker.criticalTask(); // Priority 1 - executed first
146
await priorityWorker.normalTask(); // Priority 5 - executed second
147
```
148
149
### Custom Queue Implementation
150
151
You can implement custom queue strategies by implementing the TaskQueue interface:
152
153
```typescript
154
class CustomQueue implements TaskQueue {
155
private sharedTasks: QueueChildMessage[] = [];
156
private workerTasks: Map<number, QueueChildMessage[]> = new Map();
157
158
enqueue(task: QueueChildMessage, workerId?: number): void {
159
if (workerId !== undefined) {
160
if (!this.workerTasks.has(workerId)) {
161
this.workerTasks.set(workerId, []);
162
}
163
this.workerTasks.get(workerId)!.push(task);
164
} else {
165
this.sharedTasks.push(task);
166
}
167
}
168
169
dequeue(workerId: number): QueueChildMessage | null {
170
// Custom logic: prefer worker-specific tasks on weekends
171
const isWeekend = new Date().getDay() === 0 || new Date().getDay() === 6;
172
173
const workerQueue = this.workerTasks.get(workerId) || [];
174
175
if (isWeekend && workerQueue.length > 0) {
176
return workerQueue.shift() || null;
177
}
178
179
// Otherwise, prefer shared tasks
180
return this.sharedTasks.shift() || workerQueue.shift() || null;
181
}
182
}
183
184
const customWorker = new Worker("./worker.js", {
185
taskQueue: new CustomQueue()
186
});
187
```
188
189
## Queue Behavior Patterns
190
191
### Worker-Specific vs Shared Tasks
192
193
Tasks can be enqueued for specific workers or shared among all workers:
194
195
```typescript
196
// This concept is handled internally by the Farm class
197
// When computeWorkerKey returns a key, tasks are bound to specific workers
198
const boundWorker = new Worker("./caching-worker.js", {
199
computeWorkerKey: (method, key) => {
200
// Tasks with same key always go to same worker
201
return method === "processWithCache" ? key : null;
202
}
203
});
204
205
// These will all go to the same worker (bound by key "user123")
206
await boundWorker.processWithCache("user123", "data1");
207
await boundWorker.processWithCache("user123", "data2");
208
await boundWorker.processWithCache("user123", "data3");
209
```
210
211
### Task Priority Strategies
212
213
Common priority computation patterns:
214
215
```typescript
216
// File size priority (smaller first)
217
const fileSizePriority = (method, filepath) => {
218
return fs.statSync(filepath).size;
219
};
220
221
// String length priority (shorter first)
222
const stringLengthPriority = (method, text) => {
223
return typeof text === "string" ? text.length : 0;
224
};
225
226
// Method-based priority
227
const methodPriority = (method) => {
228
const priorities = { urgent: 1, normal: 5, batch: 10 };
229
return priorities[method] || 5;
230
};
231
232
// Time-based priority (older timestamps first)
233
const timePriority = (method, timestamp) => {
234
return typeof timestamp === "number" ? timestamp : Date.now();
235
};
236
237
// Combined priority strategy
238
const combinedPriority = (method, ...args) => {
239
let priority = methodPriority(method);
240
241
if (method === "processFile" && args[0]) {
242
priority += Math.log(fs.statSync(args[0]).size);
243
}
244
245
return priority;
246
};
247
```
248
249
### Worker Scheduling Policies
250
251
Control how tasks are assigned to idle workers:
252
253
```typescript
254
const worker = new Worker("./worker.js", {
255
workerSchedulingPolicy: "round-robin" // Default: distribute evenly
256
});
257
258
const orderedWorker = new Worker("./worker.js", {
259
workerSchedulingPolicy: "in-order" // Use worker 1 first, then 2, etc.
260
});
261
```
262
263
## Queue Performance Considerations
264
265
### FIFO Queue
266
- **Best for**: Maintaining strict task ordering
267
- **Performance**: O(1) enqueue/dequeue operations
268
- **Memory**: Minimal overhead with linked list structure
269
270
### Priority Queue
271
- **Best for**: Tasks with varying importance levels
272
- **Performance**: O(log n) enqueue/dequeue operations (heap-based)
273
- **Memory**: Higher overhead due to heap maintenance
274
275
### Custom Queues
276
- **Best for**: Specialized scheduling requirements
277
- **Performance**: Depends on implementation
278
- **Memory**: Varies based on data structures used
279
280
Choose the appropriate queue based on your specific use case and performance requirements.