Live data from Hacker News

Choose Postgres queue technology

adriano.fyi

311–320 of 369 posts

Re: Choose Postgres queue technology

#311
post #152

Earlier quoted context omitted.

> This said, I'd use a dedicated queue these days. I agree, primary reason being that if you're in the cloud (thus this applies to a lot of people but obviously not everyone), all the cloud providers have extremely easy to use, and cheap , hosted queueing tech. Even if you're worried about vendor lockin, queueing primitives are so small (basically push and pop), that it's relatively easy to write things in a way so i…

Is it cheap if you already using Postgres though?

I commented elsewhere, but in most cases I think it would be a bad idea to host your queue tables and logic in the same instance that hosts your primary data. This if you spin up another PG instance in the cloud, it could very well end up costing you more than a default cloud-hosted queue service.

Re: Choose Postgres queue technology

#312

USE. ADVISORY. LOCKS. Do not use SKIP LOCKED unless it is a toy/low throughout. Row locks require transactions and disk writes. Advisory locks require neither. (However, you do have to stay inside the configurable memory budget.)

Pretty common advice for scaling Postgres is to deploy pgbouncer in transaction mode in front of it to handle connection pooling. Advisory locks don’t work in this setup (and will start behaving in strange ways if you do try to use them.) Something to consider if you go this route.

Depends. That has more to do with how your're scaling application servers.

Re: Choose Postgres queue technology

#313
post #232

Earlier quoted context omitted.

I can share our experience with RabbitMQ/SQS/Sidekiq. Our two major issues have been around the retry mechanism and resource bottlenecks. The key retry problem is "What happens when a worker crashes?". RabbitMQ solves this problem by tying "unacknowledged messages" to a tcp connection. If the connection dies, the in-flight messages are made available to other connections. This is a decent approach, but we hit a lot o…

SQS limits you further in other ways. For instance, scheduled tasks are capped to 15m (delaySconds knob), so you'll be stuck when implementing the "cancel account if not verified in 7 days" workflow. You'll either reenqueue a message every 15m until its ready (and eat your the SQS costs), or build a bespoke solution only for scheduled tasks using some other store (the database usually) and another polling loop (at a…

You could probably use AWS EventBridge and schedule the message to be posted to SQS in 7 days.

Re: Choose Postgres queue technology

#314
post #268

I've built three distributed job systems at this point. A handy rule of thumb which I have promoted for years is "build for 10x your current scale." If you need to handle 70 requests/second, design for 700. If you need to handle 20 servers running batch jobs, design for 200 servers. If you're in a startup that grows 100% per year, you'll be at 8x scale in 3 years. So you'll have time to rewrite as you grow! Out of th…

you can even built a advisory lock queue in Postgres, which is way slower but has some benefits.

Re: Choose Postgres queue technology

#315
post #314
post #268

I've built three distributed job systems at this point. A handy rule of thumb which I have promoted for years is "build for 10x your current scale." If you need to handle 70 requests/second, design for 700. If you need to handle 20 servers running batch jobs, design for 200 servers. If you're in a startup that grows 100% per year, you'll be at 8x scale in 3 years. So you'll have time to rewrite as you grow! Out of th…

you can even built a advisory lock queue in Postgres, which is way slower but has some benefits.

slower to build or slower to run?

Re: Choose Postgres queue technology

#316
post #315
post #314

Earlier quoted context omitted.

you can even built a advisory lock queue in Postgres, which is way slower but has some benefits.

slower to build or slower to run?

slower to run, but when you keep the postgres connection open you will know that the job is still running, while with for update skip locked you would need to have a status and a job_timeout basically.

so pg_try_advisory_lock/pg_advisory_unlock can lock over transactions while for update skip locked can't, thus you would either need to keep a transaction open or use status+job_timeout (and in postgres you should not use long transactions)

basically we use c#, but we looked into https://github.com/que-rb/que which uses advisory_locks, since our jobs take like 1 min to 2 hours it was a no-brainer to use advisory_locks. it's just not the best thing if you have thousands of fast jobs per second, but for a more moderate queue where you have like 10000 jobs per minute/10 minutes/30 minutes and they take like 1 min to 2 hours its fine.

we also do not delete jobs, we do not care about storage since the job table basically does not take a lot. and we have a lot of time to catchup at night since we are only in europe

Re: Choose Postgres queue technology

#317
post #288

If you're on a cloud provider, I'd say just use their offering. For small/medium amounts of messages (single digit millions a day) the cost will be trivial. A lot of frameworks already have queue/job libraries with adapters (so you're not really locked in) and cloud providers are highly scalable and fault tolerant. It seems silly to try to build into Postgres something that is already cheap and readily available unle…

> If you're on a cloud provider, I'd say just use their offering. For small/medium amounts of messages (single digit millions a day) the cost will be trivial. It's a good compromise but not suitable for every use case. The thing I really don't like is that you need to be connected to the cloud even for local development and test.

You don’t. SQS works fine in Localstack.

Re: Choose Postgres queue technology

#318
post #198
post #147

> I hope to disimbue anyone of the notion that Postgres is an inferior queue technology. I offer this correction to the author: it is "disabuse" not "disimbue".

Disimbue is also a word with an appropriate meaning-- even if it's archaic (and no longer appears in most dictionaries) and pretentious.

No, I won't believe it until I see evidence.

Did you find it in a credible source? Which one(s)?

I've found nothing credible in Merriam Webster, Etymology Online, nor _any_ other I've searched. There is at least one low-quality ad-serving site that credits ChatGPT with a definition.

I'm happy to be enlightened.

Re: Choose Postgres queue technology

#319
post #316
post #315

Earlier quoted context omitted.

slower to build or slower to run?

slower to run, but when you keep the postgres connection open you will know that the job is still running, while with for update skip locked you would need to have a status and a job_timeout basically. so pg_try_advisory_lock/pg_advisory_unlock can lock over transactions while for update skip locked can't, thus you would either need to keep a transaction open or use status+job_timeout (and in postgres you should not…

Here's my current favorite recipe for building complex job systems on PostgreSQL. I'm not thinking about "send an email"-type jobs, but bigger jobs that do complex tasks.

The usual trick I use is to have a `jobs.state` field containing "pending", "running", "done", or "error" (or whatever that job system needs). I only hold SELECT FOR UPDATE SKIPPED LOCKED long enough to:

1. Transition from "pending" to "running". Or a second time, to transition from "running" to either "done" or "error".

2. Store the current worker ID (often the Kubernetes pod name).

Then, I can build a watcher that wakes up every 5 minutes, and looks for "running" jobs with no corresponding Kubernetes pod, and mark them as "error". I try to never hold a lock for more than a second or two, and to never lock more than one job at once. This gets me 80% of the way there.

The reason I don't hold a transaction open for the entire job is because every transaction requires a PostgreSQL connection, and connections are surprisingly expensive. In fact, you may want to run connections through pgbouncer or a stateless REST API to avoid holding open hundreds or thousands of connections. Everything except PostgreSQL itself should ideally be stateless and restartable.

You might also have a retry system, or jobs that recursively queue up child jobs, or jobs that depend on other jobs, or more elaborate state machines. You might have timeouts. Most of these things are solveable with some mix of transations, some SQL, CREATE INDEX or CREATE VIEW. A database gives you so many things for free, if you're just a little careful about it.

And since Grafana supports SQL, you can easily build really nice dashboards for support and ops by just querying the tables used by the job system.

There are other ways to do it! But I'm fond of this general strategy for coarse-granularity jobs.

Re: Choose Postgres queue technology

#320
post #152

Earlier quoted context omitted.

Is it cheap if you already using Postgres though?

I commented elsewhere, but in most cases I think it would be a bad idea to host your queue tables and logic in the same instance that hosts your primary data. This if you spin up another PG instance in the cloud, it could very well end up costing you more than a default cloud-hosted queue service.

I don’t think that’s best for small things. Unless you can’t vertically scale your instance to handle to load, being able to join and keep transactions within one data store is massively valuable. I wouldn’t want to open myself to distributed systems problems unless I’m absolutely forced to.
Post reply on HN