Skip to content

Commit 0ded2d7

Browse files
authored
feat(job): allow clearing job's log (#1600)
1 parent 35bd68b commit 0ded2d7

File tree

3 files changed

+133
-1
lines changed

3 files changed

+133
-1
lines changed

src/classes/job.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ const logger = debuglog('bull');
3838

3939
const optsDecodeMap = {
4040
fpof: 'failParentOnFailure',
41+
kl: 'keepLogs',
4142
};
4243

4344
const optsEncodeMap = invert(optsDecodeMap);
@@ -446,7 +447,39 @@ export class Job<
446447
async log(logRow: string): Promise<number> {
447448
const client = await this.queue.client;
448449
const logsKey = this.toKey(this.id) + ':logs';
449-
return client.rpush(logsKey, logRow);
450+
451+
const multi = client.multi();
452+
453+
multi.rpush(logsKey, logRow);
454+
455+
if (this.opts.keepLogs) {
456+
multi.ltrim(logsKey, -this.opts.keepLogs, -1);
457+
}
458+
459+
const result = (await multi.exec()) as [
460+
[Error, number],
461+
[Error, string] | undefined,
462+
];
463+
464+
return this.opts.keepLogs
465+
? Math.min(this.opts.keepLogs, result[0][1])
466+
: result[0][1];
467+
}
468+
469+
/**
470+
* Clears job's logs
471+
*
472+
* @param keepLogs - the amount of log entries to preserve
473+
*/
474+
async clearLogs(keepLogs?: number): Promise<void> {
475+
const client = await this.queue.client;
476+
const logsKey = this.toKey(this.id) + ':logs';
477+
478+
if (keepLogs) {
479+
await client.ltrim(logsKey, -keepLogs, -1);
480+
} else {
481+
await client.del(logsKey);
482+
}
450483
}
451484

452485
/**

src/interfaces/base-job-options.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ export interface DefaultJobOptions {
5757
*/
5858
removeOnFail?: boolean | number | KeepJobs;
5959

60+
/**
61+
* Maximum amount of log entries that will be preserved
62+
*/
63+
keepLogs?: number;
64+
6065
/**
6166
* Limits the amount of stack trace lines that will be recorded in the stacktrace.
6267
*/

tests/test_job.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,100 @@ describe('Job', function () {
355355
const logsRemoved = await queue.getJobLogs(job.id);
356356
expect(logsRemoved).to.be.eql({ logs: [], count: 0 });
357357
});
358+
359+
it('should preserve up to keepLogs latest entries', async () => {
360+
const firstLog = 'some log text 1';
361+
const secondLog = 'some log text 2';
362+
const thirdLog = 'some log text 3';
363+
364+
const job = await Job.create(
365+
queue,
366+
'test',
367+
{ foo: 'bar' },
368+
{ keepLogs: 2 },
369+
);
370+
371+
const count1 = await job.log(firstLog);
372+
expect(count1).to.be.equal(1);
373+
374+
const logs1 = await queue.getJobLogs(job.id);
375+
expect(logs1).to.be.eql({ logs: [firstLog], count: 1 });
376+
377+
const count2 = await job.log(secondLog);
378+
expect(count2).to.be.equal(2);
379+
380+
const logs2 = await queue.getJobLogs(job.id);
381+
expect(logs2).to.be.eql({ logs: [firstLog, secondLog], count: 2 });
382+
383+
const count3 = await job.log(thirdLog);
384+
expect(count3).to.be.equal(2);
385+
386+
const logs3 = await queue.getJobLogs(job.id);
387+
expect(logs3).to.be.eql({ logs: [secondLog, thirdLog], count: 2 });
388+
});
389+
});
390+
391+
describe('.clearLogs', () => {
392+
it('can clear the log', async () => {
393+
const firstLog = 'some log text 1';
394+
const secondLog = 'some log text 2';
395+
396+
const job = await Job.create(queue, 'test', { foo: 'bar' });
397+
398+
await job.log(firstLog);
399+
await job.log(secondLog);
400+
const logs = await queue.getJobLogs(job.id);
401+
expect(logs).to.be.eql({ logs: [firstLog, secondLog], count: 2 });
402+
403+
await job.clearLogs();
404+
405+
const logsRemoved = await queue.getJobLogs(job.id);
406+
expect(logsRemoved).to.be.eql({ logs: [], count: 0 });
407+
});
408+
409+
it('can preserve up to keepLogs latest entries', async () => {
410+
const firstLog = 'some log text 1';
411+
const secondLog = 'some log text 2';
412+
const thirdLog = 'some log text 3';
413+
414+
const job = await Job.create(queue, 'test', { foo: 'bar' });
415+
416+
await job.log(firstLog);
417+
await job.log(secondLog);
418+
await job.log(thirdLog);
419+
420+
const logs1 = await queue.getJobLogs(job.id);
421+
expect(logs1).to.be.eql({
422+
logs: [firstLog, secondLog, thirdLog],
423+
count: 3,
424+
});
425+
426+
await job.clearLogs(4);
427+
428+
const logs2 = await queue.getJobLogs(job.id);
429+
expect(logs2).to.be.eql({
430+
logs: [firstLog, secondLog, thirdLog],
431+
count: 3,
432+
});
433+
434+
await job.clearLogs(3);
435+
436+
const logs3 = await queue.getJobLogs(job.id);
437+
expect(logs3).to.be.eql({
438+
logs: [firstLog, secondLog, thirdLog],
439+
count: 3,
440+
});
441+
442+
await job.clearLogs(2);
443+
444+
const logs4 = await queue.getJobLogs(job.id);
445+
expect(logs4).to.be.eql({ logs: [secondLog, thirdLog], count: 2 });
446+
447+
await job.clearLogs(0);
448+
449+
const logsRemoved = await queue.getJobLogs(job.id);
450+
expect(logsRemoved).to.be.eql({ logs: [], count: 0 });
451+
});
358452
});
359453

360454
describe('.moveToCompleted', function () {

0 commit comments

Comments
 (0)