Skip to content

Commit 7e9570d

Browse files
committed
refactor: every driver handles serializing the job payload
Before all drivers would just get a payload string, but now each get payload unknown and depending on their capabilities they can decide how to store it. mongo db: an object sqlite: jsonb column memory: just an object file: json string redis: json string sqs: json string
1 parent 1345e53 commit 7e9570d

14 files changed

Lines changed: 628 additions & 551 deletions

File tree

src/core/queue.ts

Lines changed: 194 additions & 108 deletions
Large diffs are not rendered by default.

src/drivers/db.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Queue } from '../core/queue.ts';
22
import type { JobStatus, JobMeta, QueueMessage, BaseJobOptions, WithPriority, WithDelay } from '../interfaces/job.ts';
3-
import type { DatabaseAdapter, QueueJobRecord } from '../interfaces/database.ts';
3+
import type { DatabaseAdapter } from '../interfaces/database.ts';
44
import type { QueueOptions } from '../interfaces/plugin.ts';
55

66
// Driver-specific job request interface
@@ -23,8 +23,8 @@ export class DbQueue<TJobMap = Record<string, any>> extends Queue<TJobMap, DbJob
2323
return this.db;
2424
}
2525

26-
protected async pushMessage(payload: string, meta: JobMeta): Promise<string> {
27-
return await this.db.insertJob(Buffer.from(payload), meta);
26+
protected async pushMessage(payload: unknown, meta: JobMeta): Promise<string> {
27+
return await this.db.insertJob(payload, meta);
2828
}
2929

3030
protected async reserve(timeout: number): Promise<QueueMessage | null> {
@@ -34,15 +34,10 @@ export class DbQueue<TJobMap = Record<string, any>> extends Queue<TJobMap, DbJob
3434
return null;
3535
}
3636

37-
const payload = record.payload.toString();
38-
// Extract job name from payload
39-
const jobData = JSON.parse(payload);
40-
4137
return {
4238
id: record.id,
43-
name: jobData.name,
44-
payload,
45-
meta: record.meta
39+
payload: record.payload,
40+
meta: record.meta,
4641
};
4742
}
4843

src/drivers/file.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,12 @@ export class FileQueue<TJobMap = Record<string, any>> extends Queue<TJobMap, Fil
6262
}
6363
}
6464

65-
protected async pushMessage(payload: string, meta: JobMeta): Promise<string> {
65+
protected async pushMessage(payload: unknown, meta: JobMeta): Promise<string> {
6666
const id = await this.touchIndex(async (data) => {
6767
const jobId = String(++data.lastId);
6868
const jobPath = path.join(this.path, `job${jobId}.data`);
6969

70-
await fs.writeFile(jobPath, payload, 'utf8');
70+
await fs.writeFile(jobPath, JSON.stringify({ payload, meta }), 'utf8');
7171
if (this.fileMode !== undefined) {
7272
await fs.chmod(jobPath, this.fileMode);
7373
}
@@ -137,17 +137,14 @@ export class FileQueue<TJobMap = Record<string, any>> extends Queue<TJobMap, Fil
137137

138138
if (reserved) {
139139
const jobPath = path.join(this.path, `job${reserved.id}.data`);
140-
const payload = await fs.readFile(jobPath, 'utf8');
141-
142-
// Extract job name from payload
143-
const jobData = JSON.parse(payload);
140+
const { payload, meta } = JSON.parse(await fs.readFile(jobPath, 'utf8'));
144141

145142
return {
146143
id: reserved.id,
147-
name: jobData.name,
148144
payload,
149145
meta: {
150-
ttr: reserved.ttr
146+
ttr: reserved.ttr,
147+
name: meta.name,
151148
}
152149
};
153150
}

src/drivers/memory.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export interface InMemoryJobRequest<TPayload> extends BaseJobOptions, WithPriori
1111

1212
interface InMemoryJobRecord {
1313
id: string;
14-
payload: string;
14+
payload: unknown;
1515
meta: JobMeta;
1616
status: 'waiting' | 'reserved' | 'done' | 'failed';
1717
pushedAt: Date;
@@ -86,7 +86,7 @@ export class InMemoryQueue<TJobMap = Record<string, any>> extends Queue<TJobMap,
8686
this.maxJobs = options.maxJobs || 1000;
8787
}
8888

89-
protected async pushMessage(payload: string, meta: JobMeta): Promise<string> {
89+
protected async pushMessage(payload: unknown, meta: JobMeta): Promise<string> {
9090
const id = (this.nextJobId++).toString();
9191
const now = new Date();
9292

@@ -154,12 +154,8 @@ export class InMemoryQueue<TJobMap = Record<string, any>> extends Queue<TJobMap,
154154

155155
this.ttrTimeouts.set(jobId, ttrTimeout);
156156

157-
// Extract job name from payload
158-
const jobData = JSON.parse(job.payload);
159-
160157
return {
161158
id: jobId,
162-
name: jobData.name,
163159
payload: job.payload,
164160
meta: job.meta
165161
};

src/drivers/mongoose.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export interface MongooseJobRequest<TPayload>
2525
// MongoDB document structure for queue jobs
2626
export interface IQueueJobDocument {
2727
payload: any;
28+
name: string;
2829
ttr: number;
2930
delaySeconds: number;
3031
priority: number;
@@ -46,6 +47,7 @@ export interface IQueueJob extends IQueueJobDocument, Document {
4647
// Queue job schema
4748
export const QueueJobSchema = new Schema<IQueueJob>(
4849
{
50+
name: { type: String, required: true },
4951
payload: { type: Schema.Types.Mixed, required: true },
5052
ttr: { type: Number, required: true, default: 300 },
5153
delaySeconds: { type: Number, required: true, default: 0 },
@@ -79,12 +81,13 @@ QueueJobSchema.index({ _id: 1, status: 1 });
7981
export class MongooseDatabaseAdapter implements DatabaseAdapter {
8082
constructor(private model: Model<IQueueJob>) {}
8183

82-
async insertJob(payload: any, meta: JobMeta): Promise<string> {
84+
async insertJob(payload: unknown, meta: JobMeta): Promise<string> {
8385
const now = new Date();
8486

8587
const doc = await this.model
8688
.create({
8789
payload,
90+
name: meta.name,
8891
ttr: meta.ttr ?? 300,
8992
delaySeconds: meta.delaySeconds ?? 0,
9093
priority: meta.priority ?? 0,
@@ -166,14 +169,15 @@ export class MongooseDatabaseAdapter implements DatabaseAdapter {
166169

167170
return {
168171
id: doc._id.toHexString(),
169-
payload: doc.payload,
170172
meta: {
173+
name: doc.name,
171174
ttr: doc.ttr,
172175
delaySeconds: doc.delaySeconds,
173176
priority: doc.priority,
174177
pushedAt: doc.pushTime,
175178
reservedAt: now,
176179
},
180+
payload: doc.payload,
177181
pushedAt: doc.pushTime,
178182
reservedAt: now,
179183
};

src/drivers/redis.ts

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,11 @@ export class RedisQueue<TJobMap = Record<string, any>> extends Queue<TJobMap, Re
6969
this.redis = redisClient;
7070
}
7171

72-
protected async pushMessage(payload: string, meta: JobMeta): Promise<string> {
72+
protected async pushMessage(payload: unknown, meta: JobMeta): Promise<string> {
7373
const id = (await this.redis.incr(this.idKey)).toString();
74-
const ttr = meta.ttr || this.ttrDefault;
7574
const now = Math.floor(Date.now() / 1000);
7675

77-
// Store message in Yii2 format: "ttr;jsonPayload"
78-
const message = `${ttr};${payload}`;
76+
const message = JSON.stringify({ payload, meta });
7977
await this.redis.hSet(this.messagesKey, id, message);
8078

8179
if (meta.delaySeconds && meta.delaySeconds > 0) {
@@ -142,32 +140,21 @@ export class RedisQueue<TJobMap = Record<string, any>> extends Queue<TJobMap, Re
142140
return null;
143141
}
144142

145-
// Parse Yii2 format: "ttr;jsonPayload"
146-
const separatorIndex = message.indexOf(';');
147-
if (separatorIndex === -1) {
148-
return null;
149-
}
150-
151-
const ttr = parseInt(message.substring(0, separatorIndex));
152-
const payloadStr = message.substring(separatorIndex + 1);
143+
const { payload, meta } = JSON.parse(message) as { payload: unknown, meta: JobMeta };
153144

154145
// Reserve the job
155-
const expireAt = now + ttr;
146+
const expireAt = now + (meta.ttr || this.ttrDefault);
156147
await this.redis.zAdd(this.reservedKey, { score: expireAt, value: id });
157148

158149
// Increment attempt counter
159150
await this.redis.hIncrBy(this.attemptsKey, id, 1);
160151

161-
// Extract job name from payload
162-
const jobData = JSON.parse(payloadStr);
163-
164152
return {
165153
id,
166-
name: jobData.name,
167-
payload: payloadStr,
154+
payload,
168155
meta: {
169-
ttr,
170-
pushedAt: new Date()
156+
ttr: meta.ttr || this.ttrDefault,
157+
name: meta.name,
171158
}
172159
};
173160
}

0 commit comments

Comments
 (0)