Skip to content

Commit 2b4f40d

Browse files
Boris Dorofeevnodkz
Boris Dorofeev
authored andcommitted
feat: limit job data size for all addJob mutations
relates: #83
1 parent de890b9 commit 2b4f40d

File tree

6 files changed

+52
-0
lines changed

6 files changed

+52
-0
lines changed

src/definitions.ts

+1
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ export type Options = {
1111
};
1212
redis?: RedisOptions | Redis;
1313
redisEvents?: RedisOptions | Redis;
14+
maxSizeOfJobData?: number /** in bytes */;
1415
};

src/helpers/roughSizeOfObject.ts

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { Options } from '../definitions';
2+
3+
function roughSizeOfObject(object: unknown): number {
4+
const objectList = [];
5+
const stack = [object];
6+
let bytes = 0;
7+
8+
while (stack.length) {
9+
const value = stack.pop();
10+
11+
if (typeof value === 'boolean') {
12+
bytes += 4;
13+
} else if (typeof value === 'string') {
14+
bytes += value.length * 2;
15+
} else if (typeof value === 'number') {
16+
bytes += 8;
17+
} else if (typeof value === 'object' && objectList.indexOf(value as never) === -1) {
18+
objectList.push(value as never);
19+
20+
for (const i in value) {
21+
stack.push(value[i]);
22+
}
23+
}
24+
}
25+
return bytes;
26+
}
27+
28+
export const defaultMaxSizeOfObjectData = 10000;
29+
30+
export function checkJobDataSize(opts: Options, data: unknown): void {
31+
const allowableSize = opts?.maxSizeOfJobData || defaultMaxSizeOfObjectData;
32+
const size = roughSizeOfObject(data);
33+
if (size > allowableSize) {
34+
throw new Error(`Job data ${size} exceeds allowable size ${allowableSize}`);
35+
}
36+
}

src/mutation/jobAdd.ts

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { getJobTC } from '../types/job/Job';
33
import { findQueue } from '../helpers';
44
import { Options } from '../definitions';
55
import { createJobDataITC } from '../types/job/JobInput';
6+
import { checkJobDataSize } from '../helpers/roughSizeOfObject';
67

78
export function createJobAddFC(
89
sc: SchemaComposer<any>,
@@ -44,6 +45,7 @@ export function createJobAddFC(
4445
}),
4546
},
4647
resolve: async (_, { prefix, queueName, jobName, data, options }) => {
48+
checkJobDataSize(opts, data);
4749
const queue = await findQueue(prefix, queueName, opts);
4850
const job = await queue.add(jobName, data, options);
4951
return {

src/mutation/jobAddBulk.ts

+9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { findQueue } from '../helpers';
22
import { SchemaComposer, ObjectTypeComposerFieldConfigAsObjectDefinition } from 'graphql-compose';
33
import { getJobTC } from '../types/job/Job';
44
import { Options } from '../definitions';
5+
import { checkJobDataSize } from '../helpers/roughSizeOfObject';
56

67
export function createJobAddBulkFC(
78
sc: SchemaComposer<any>,
@@ -46,6 +47,14 @@ export function createJobAddBulkFC(
4647
}).List,
4748
},
4849
resolve: async (_, { prefix, queueName, jobs }) => {
50+
if (Array.isArray(jobs)) {
51+
for (const job of jobs) {
52+
checkJobDataSize(opts, job);
53+
}
54+
} else {
55+
throw new Error('jobAddBulk: jobs argument must be an array');
56+
}
57+
4958
const queue = await findQueue(prefix, queueName, opts);
5059
const jobsRes = await queue.addBulk(jobs);
5160
return {

src/mutation/jobAddCron.ts

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { findQueue } from '../helpers';
22
import { SchemaComposer, ObjectTypeComposerFieldConfigAsObjectDefinition } from 'graphql-compose';
33
import { getJobTC } from '../types/job/Job';
44
import { Options } from '../definitions';
5+
import { checkJobDataSize } from '../helpers/roughSizeOfObject';
56

67
export function createJobAddCronFC(
78
sc: SchemaComposer<any>,
@@ -54,6 +55,7 @@ export function createJobAddCronFC(
5455
}),
5556
},
5657
resolve: async (_, { prefix, queueName, jobName, data, options }) => {
58+
checkJobDataSize(opts, data);
5759
const queue = await findQueue(prefix, queueName, opts);
5860
const job = await queue.add(jobName, data, options);
5961
return {

src/mutation/jobAddEvery.ts

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { findQueue } from '../helpers';
22
import { SchemaComposer, ObjectTypeComposerFieldConfigAsObjectDefinition } from 'graphql-compose';
33
import { getJobTC } from '../types/job/Job';
44
import { Options } from '../definitions';
5+
import { checkJobDataSize } from '../helpers/roughSizeOfObject';
56

67
export function createJobAddEveryFC(
78
sc: SchemaComposer<any>,
@@ -53,6 +54,7 @@ export function createJobAddEveryFC(
5354
}),
5455
},
5556
resolve: async (_, { prefix, queueName, jobName, data, options }) => {
57+
checkJobDataSize(opts, data);
5658
const queue = await findQueue(prefix, queueName, opts);
5759
const job = await queue.add(jobName, data, options);
5860
return {

0 commit comments

Comments
 (0)