I have a product which uses two separate tables as queues for some processes. Generally speaking:
- Interesting events occur in the application, and we write a record to the appropriate queue. That "queued" record points to another table whose records are a long-lasting record of the thing having been processed.
- A background process comes along and processes the queue later, marks the job as "complete" and deletes the record from the queue.
This setup gives us several advantages over simply having the application do whatever the queue-processor is going to do:
- If the action to be taken is long-running for some reason, the application need not be blocked.
- If the action fails, it can be re-tried the next time the queue-processor runs.
- The queue-processors can be multi-process/thread is desired.
Mostly I'm just describing reasons to use queues above, it of course has nothing to do with using the db as the underlying structure.
We are looking at "advantage #3' above a little closely, and expanding our queue-processors to be not just multi-process but also multi-server which means we need to be a little more careful about how we process that queue, because each item must only be successfully processed once. Two or more times is generally not okay.
So one of the questions we naturally asked ourselves was "well, should we even be using the database for this queue?"
That got me to thinking about how we use the queue, and why we might not want to do it this way. Briefly:
SELECT id, queued_thing_id FROM queue WHERE [fairly general WHERE clause] FOR UPDATE
- For each record:
- Do stuff
UPDATE queued_things SET status='complete', completed_date=NOW() WHERE id=[queued_thing_id]
DELETE FROM queue WHERE id=[id]
Potential reasons not to use a db:
"This is wasteful."
No it's not. The records are very compact.
"Yeah but the table will grow forever."
No it won't. Every DELETE makes room for another row. We aren't talking about millions of
INSERT
s andDELETE
s at a time, here. Okay, maybe we'll have two whole db pages allocated all the time, but it's not like the file will grow forever just because the data are being cyclicly added and removed."There are other products that are better at this."
Sure, but we aren't using those products at this point. This is a working solution that does not seem to have any significant negatives.
So, it all comes down to whether or not we have correctly assessed the "risks" of using an InnoDB table as a queue. Other than "relational databases aren't a great choice for a queue because other products are better," are there any specific technical reasons to abandon a working solution based upon MySQL/MariaDB/InnoDB? I don't even think we need to periodically run an OPTIMIZE TABLE
on these queues because they ought to maintain themselves, right?
Update 2022-11-21
As requested, some details:
We gather tasks based upon human actions, and we don't have enormous volume like Twitter or whatever. Several dozen tasks per minute are being queued and we run the queue-processor once per minute.
Tasks are indeed idempotent. They either totally succeed or totally fail, and are re-tried on the next attempt.
We stop trying after several attempts to avoid repeatedly-processing the same failing tasks.
We are not currently setting
innodb_lock_wait_timeout
for these queue-processors (we currently only have a single one, and would like to add a second one to simply not have a single point-of-failure), but we should probably go ahead and set that to some relatively low value, because if a processor is actively running, there is no need to rhave another one waiting on a lock. It can simply go back to sleep and try again later.
Given the above, I think while this is not a "toy project", it's still well within the realm of being "okay until it's not." Introducing a new paradigm and new software to the mix (on short notice) are probably not (yet) warranted.
I very much appreciate everyone's thoughts on the matter.