Skip to content

Commit 60e9a1e

Browse files
authored
Merge pull request #1 from StatelessStudio/v1.0.0
V1.0.0
2 parents 70c482a + 92e35f5 commit 60e9a1e

22 files changed

Lines changed: 1735 additions & 450 deletions

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
11
# ts-task-queue
2+
3+
## [1.0.0]
4+
5+
Initial Release

README.md

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,153 @@
11
# ts-task-queue
2+
3+
Create & queue tasks on a pool of workers.
4+
5+
## Installation
6+
7+
`npm i ts-task-queue`
8+
9+
## Usage
10+
11+
In this example, we'll create a queue that will add two numbers.
12+
13+
### 1. Declare the task interface
14+
15+
Create a file for the queue, `src/add-queue.ts`. In this file, we'll create an interface that will be used for our task.
16+
17+
Our add task will accept two inputs, `a` and `b`, which must both be numbers:
18+
19+
`src/add-queue.ts`
20+
```typescript
21+
export interface AddTask {
22+
a: number;
23+
b: number;
24+
}
25+
```
26+
27+
### 2. Create a queue
28+
29+
Our task will take an `AddTask` as input, and output a number (the sum). So we'll create a queue that takes an AddTask as input and returns a number `new Queue<AddTask, number>()`.
30+
31+
32+
`src/add-queue.ts`
33+
```typescript
34+
export interface AddTask {
35+
a: number;
36+
b: number;
37+
}
38+
39+
export const addQueue = new Queue<AddTask, number>({
40+
41+
});
42+
```
43+
44+
### 3. Setup the queue
45+
46+
At a minimum, our queue needs a `name` and a `callback`. The name must be a unique string to identify the queue, and the callback is a function that will perform the work that this queue does. The callback must be an async function!
47+
48+
`src/add-queue.ts`
49+
```typescript
50+
export interface AddTask {
51+
a: number;
52+
b: number;
53+
}
54+
55+
export const addQueue = new Queue<AddTask, number>({
56+
name: 'add-queue',
57+
callback: async (task: AddTask) => task.a + task.b,
58+
});
59+
```
60+
61+
### 4. Use the queue
62+
63+
We can use `addQueue.await()` to push tasks onto the queue and get a Promise back. You most likely will want to wrap your application startup in `Queue.isMainThread()`; so you're not running application code on the worker that should only be run on the main thread:
64+
65+
`src/index.ts`
66+
```typescript
67+
import { AddTask, addQueue } from './add-queue';
68+
69+
if (addQueue.isMainThread()) {
70+
const sum = await addQueue.await({ a: 4, b: 8 });
71+
72+
console.log('Sum is', sum);
73+
// Sum is 12
74+
}
75+
```
76+
77+
### 5. (Optional) Using with ts-node
78+
79+
If you plan to run this through ts-node, you will also need to create a javascript entry-point for the workers:
80+
81+
`./index.js`
82+
```javascript
83+
/**
84+
* This file boots the worker in dev when the project is run through ts-node.
85+
* - This file is not included in the build.
86+
*/
87+
if (!process.execArgv.includes('ts-node/register')) {
88+
require('ts-node').register();
89+
}
90+
91+
const path = require('path');
92+
require(path.resolve(__dirname, './src/index.ts'));
93+
```
94+
95+
### 6. Using multiple queues
96+
97+
To run different tasks on multiple queues, you can repeat steps 1-4 to create additional queues. Just make sure the name is unique!
98+
99+
`src/subtract-queue.ts`
100+
```typescript
101+
102+
export interface SubtractTask {
103+
a: number;
104+
b: number;
105+
};
106+
107+
export subtractQueue = new Queue<SubtractTask, number>({
108+
name: 'subtract-queue',
109+
callback: async (task: SubtractTask) => task.a - task.b,
110+
});
111+
```
112+
113+
`src/index.ts`
114+
```typescript
115+
import { AddTask, addQueue } from './add-queue';
116+
import { SubtractTask, subtractQueue } from './subtract-queue';
117+
118+
if (addQueue.isMainThread()) {
119+
const sum = await addQueue.await({ a: 4, b: 8 });
120+
console.log('Sum is', sum);
121+
// Sum is 12
122+
}
123+
124+
if (subtractQueue.isMainThread()) {
125+
const diff = await subtractQueue.await({ a: 6, b: 4 });
126+
console.log('Difference is', diff);
127+
// Difference is 2
128+
}
129+
```
130+
131+
## Customizing the Queue
132+
133+
Use the following options to customize the queue:
134+
135+
### workerEntry
136+
137+
Specify a different file to load the workers. Default is index.js or the main file from package.json
138+
139+
### nWorkers
140+
141+
Number of workers pooled for the queue. Default is 4
142+
143+
### startup
144+
145+
Run a function on worker startup, e.g. establish database connection
146+
147+
### error
148+
149+
Specify an error-handler function. Default logs to stderr
150+
151+
### fatal
152+
153+
Specify a fatal error-handler function. Default logs to stderr and exits

example/fibonacci.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export function fibonacci(num: number): number {
2+
if (num <= 1) {
3+
return num;
4+
}
5+
6+
return fibonacci(num - 1) + fibonacci(num - 2);
7+
}
8+
9+
export function timeFibonacci(num: number): number {
10+
const start = Date.now();
11+
12+
fibonacci(num);
13+
14+
return Date.now() - start;
15+
}

example/index.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* This file boots the worker in dev when the project is run through ts-node.
3+
* - This file is not included in the build.
4+
*/
5+
if (!process.execArgv.includes('ts-node/register')) {
6+
require('ts-node').register();
7+
}
8+
9+
const path = require('path');
10+
require(path.resolve(__dirname, './index.ts'));

example/index.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { timeFibonacci } from './fibonacci';
2+
import { log } from './log';
3+
import { fibonacciQueue } from './queue';
4+
5+
if (fibonacciQueue.isMainThread()) {
6+
log.info('Starting main thread...');
7+
8+
const n = 30;
9+
10+
// Run a single fib on the main thread as a control
11+
log.info('main thread took', timeFibonacci(n));
12+
13+
const start = Date.now();
14+
15+
const p1 = fibonacciQueue.await(n)
16+
.then((res: number) => log.info('First worker complete in (ms)', res))
17+
.catch(log.error);
18+
19+
const p2 = fibonacciQueue.await(n)
20+
.then((res: number) => log.info('Second worker complete in (ms)', res))
21+
.catch(log.error);
22+
23+
const p3 = fibonacciQueue.await(n)
24+
.then((res: number) => log.info('Third worker complete in (ms)', res))
25+
.catch(log.error);
26+
27+
Promise.all([p1, p2, p3])
28+
.then(() => {
29+
const time = Date.now() - start;
30+
log.info('All took (ms) ' + time);
31+
})
32+
.catch(log.error);
33+
}

example/log.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { Log } from 'ts-tiny-log';
2+
3+
export const log = new Log();

example/queue.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Queue } from '../src';
2+
import { log } from './log';
3+
import { timeFibonacci } from './fibonacci';
4+
5+
/**
6+
* Worker threads
7+
*/
8+
export const fibonacciQueue = new Queue<number, number>({
9+
name: 'fibonacci',
10+
workerEntry: __dirname,
11+
nWorkers: 4,
12+
callback: async (num) => timeFibonacci(num),
13+
});

0 commit comments

Comments
 (0)