8000 Making `DatabaseQueue` production-ready · Issue #1364 · laravel/ideas · GitHub
[go: up one dir, main page]

Skip to content
This repository was archived by the owner on Jul 16, 2021. It is now read-only.
This repository was archived by the owner on Jul 16, 2021. It is now read-only.
Making DatabaseQueue production-ready #1364
@kelvinj

Description

@kelvinj

This is my take on the issues with the DatabaseQueue adapter in Laravel.

Problems

Deadlocks

People are running the database queue adapter in production, even if Taylor has said it's not intended for production use.

The issues arise when running multiple queue workers. The DatabaseQueue adapter queries the jobs table to find an appropriate job to do, and if one is found, and update is performed to ensure no other workers try to take it. Because of this 2-step process, and to avoid race conditions, queries within the adapter use lockForUpdate(), which in some situations leads to deadlocks. I have witnessed that the more workers you have, the increasing likelihood of deadlocking.

Data loss potential

One other current issue, as I see it, is the possibility of losing a job when attempting to release back onto the queue because:

  1. The release is done in 2 steps – the original record is deleted, and a new record is inserted
  2. The above is not done in a single transaction – a lost DB connection after the first could lose data

Solution

Deadlocks

My solution would be to flip around the SELECT and UPDATE operations in a way that would avoid the need for transactions. Popping a job off the queue would look like this:

  1. Generate a random string (str_random()) used as a temporary identifier for the current process of taking a job
  2. Use an UPDATE similar to the SELECT query in DatabaseQueue::getNextAvailableJob, whereby the temporary identifier is stored against an available job, and LIMIT 1 used to only affect 1 record
  3. A SELECT query to find the job using the temporary identifier could only return 1 job, but there would be no need for a transaction and a lock.

Because of this process, there would be no need to use lockForUpdate() when deleting / releasing the job either.

A change would be required to the jobs / failed_job table schemas to store the temp identifier.

Data loss potential

This would be remedied by wrapping the 2 operations in a transaction.


Thoughts?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0