Skip to content

Race between queue.RequestJobForProcessing and queue.AddJob #53

@emcodem

Description

@emcodem

Hi @hajipy, thanks for this repository!

As i spent a lot of time debugging this, i would like to share my experiences so it can be either fixed or others can profit from it:
What i experienced was that a job was executed twice without any obvious reason.

In a nutshell, my code does about this:

const ingest_queue= await EmbeddedQueue.Queue.createQueue({ inMemoryOnly:true});
ingest_queue.process(
	"1234_randomqueuname",
	async (job) => ingestWorker(job),
	5 
);
await global.queues.ingest_queue.createJob({
	type: "1234_randomqueuname",
	data: someJobData
}

I did some debugging and it seems to turn out that the reason why this job is executed twice is that the setup of the workers (queue.RequestJobForProcessing ) is still ongoing while queue.AddJob is called.
AddJob can then notice that a worker is already waiting (in this.waitingRequests) so it marks the job in the database as active and resolves the promise of the first available worker.

So far so good but meanwhile, at the same time, another worker is in preparation (as we specified 5 workers at queue setup), it searches the database for inactive jobs and finds one (the one that AddJob just marks as Active, but this process did not yet finish).
So in the end, RequestJobForProcessing does not put the worker into waitingRequests but instead it also resolves the promise with the job it has got from database.

My solution for it is to double check if the job is really inactive in RequestJobForProcessing:

let neDbJob = await this.repository.findInactiveJobByType(type);
await sleep(2);
neDbJob = await this.repository.findInactiveJobByType(type);

It seems to solve my issue but of course it is not a solution.
Probably using a lock around findInactiveJobByType and setStateActive would be the real solution, not sure about it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions