News for hackers. Stuff that matters.
Re:Turning PostgreSQL into a queue serving 10k jobs per seco... by bloody-crow on Thursday November 14, 2019 @12:22PM (#21537271)
One of the interesting unforeseen downsides of RDBMS-based queues is explored here: https://brandur.org/postgres-queues

TDLR the lock time grows exponentially depending on the number of dead tuples in the table, which naturally grows as you use long running transactions.

Re:Turning PostgreSQL into a queue serving 10k jobs per seco... by bgentry on Thursday November 14, 2019 @12:36PM (#21537414)
While this is a great article and was completely accurate as of the time it was written, I believe it predates SKIP LOCKED, as well as some of the more recent design changes in Que which minimize the likielihood of this being an issue: https://www.2ndquadrant.com/en/blog/what-is-select-skip-lock...

In particular, Que’s new design locks jobs in a single connection per worker process, not a connection per-job. Job assignments are handled in an in-memory/unlogged table. Jobs are also automatically assigned to a free worker upon being enqueued via LISTEN/NOTIFY and an unlogged table of available workers. And jobs are locked in batches by each worker process, not one-at-a-time. So polling becomes much less frequent and is far more efficient when it happens.

This does not mean that it’s suddenly ok for jobs to take out transactions which run a long time (that is usually a bad idea in a production database) but it does substantially minimize the scenarios where these problems might occur.

Re:Turning PostgreSQL into a queue serving 10k jobs per seco... by bloody-crow on Thursday November 14, 2019 @01:31PM (#21537958)
TIL. This is very useful. I believe 9.4 was the latest version around the time the article was published.

I'm glad the state of things has improved, since I really love database-backed job queues and all transactional guarantees it gives you.

Re:Turning PostgreSQL into a queue serving 10k jobs per seco... by olefoo on Thursday November 14, 2019 @09:13PM (#21541670)
If you are experiencing this problem look at your autovacuum settings; postgres ( versions > 9.0 ) can take per table settings for autovacuum.

Percona has a good article on this https://www.percona.com/blog/2018/08/10/tuning-autovacuum-in...

Re:Turning PostgreSQL into a queue serving 10k jobs per seco... by Exuma on Thursday November 14, 2019 @12:24PM (#21537296)
Is that fixed by the VACUUM process?
Re:Turning PostgreSQL into a queue serving 10k jobs per seco... by bloody-crow on Thursday November 14, 2019 @12:34PM (#21537398)
No, cause VACUUM can't kill those dead tuples while transaction is still running. Think of it this way...

When you open a transaction, you need to have a guarantee that you can touch rows that existed at the moment when transaction has started. You job queue is chugging along and processes let's say a 1000 jobs per minute. Processing a job involves deleting the row from the queue, but since you have a transaction running, Postgres only marks the row as deleted, and keeps it around in case a transaction would want to access it at some point. Each time you need to process a job, Postgres needs to lock the row. The way this mechanism works involves iterating over the rows until you find one you can lock on. If your transaction is running 30 minutes, each job would have to iterate through 30k dead rows (deleted, but still around for the sake of the transaction). Slowing down lock time leads to overal degreaded performance of the job queue, which leads to jobs being added faster than they're being processed, which further exacerbates the problem

Re:Turning PostgreSQL into a queue serving 10k jobs per seco... by biggestdecision on Thursday November 14, 2019 @02:40PM (#21538619)
I wonder if this could be solved by moving in-progress jobs to a separate table...

Guess you lose job atomicity that way.

Re:Turning PostgreSQL into a queue serving 10k jobs per seco... by taesko on Thursday November 14, 2019 @12:33PM (#21537386)
It naturally grows due to long running transactions because the vacuum process cannot clean dead tuples that a transaction can "see". Though more aggressive vacuum settings might solve this problem.