sorentwo

sorentwo OP

Oban Core Team

This is purely a comparison of how the libraries are structured and their features. Between building Kiq and Oban I investigated nearly every library in the ecosystem (EctoJob, Exq, Honeydew, Que, Rihanna and Verk). I learned something from each one and owe all of the authors a debt of gratitude.

There are far too many differences between the various libraries to summarize them here. Therefore I’m going to cheat a bit and make a table highlighting the differences between only the libraries you asked about.

Feature Oban EctoJob Rihanna
perform return output doesn’t matter multi transaction success tuple
job scheduling triggered, polled triggered, polled polled
args storage jsonb jsonb erlang terms
error retention all full historic errors none last error
execution time unlimited configured timeout unlimited
orphaned jobs rescued, guarded by locks inside a transaction guarded by locks
queues multiple with single table one per table single
queue limits configured limit per queue configured limit per queue configured globally
queue changes pause, resume, scale none none
graceful shutdown worker draining no no
job cancelling yes no no
runtime metrics with telemetry no no
historic metrics with retained jobs no no
integrations with telemetry, pubsub no no

This is all based on my understanding of the other libraries through docs, issues and source code. It may not be entirely accurate! If I got anything wrong please let me know (@mbuhot @lpil)

23
Post #21
Exadra37

Exadra37

Congrats on this excellent work :slightly_smiling_face:

I want to call your attention for the fact that you are leaking emails from your real customers in the screenshot of the web UI, and that can cause you legal issues, like with GDPR.

1
Post #22
benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Can you elaborate on the usage of advisory locks? One serious downside to advisory locks is that they are effectively a shared namespace. We use them within our own application, and it’s entirely possible that the ids in the job row will conflict with the values locked for some other purpose.

1
Post #23
sorentwo

sorentwo OP

Oban Core Team

Ah, I should have mentioned that everything in the dashboard is generated from “faker” data. There isn’t anything sensitive in the screenshot—in fact the only real part is that my laptop is called SorenBook =)

The host app where the UI live view is mounted generates a constant stream of fake jobs in various queues. This has been really helpful for testing with pseudo-production data.

3
Post #24
lpil

lpil

Creator of Gleam

Very cool! A few notes on Rihanna:

The latest error is retained in the job’s database record.
Orphaned jobs are not possible, when a node goes down the lock is released and they will be picked up on next poll.
Jobs can be deleted, though outside the Rihanna UI project this feature isn’t made overly accessible.

Non-global configuration, graceful shutdown, and multiple queues within a single table are all pretty straightforward to add and have open issues. If there’s a demand for them they can be implemented :slight_smile:

Rihanna uses them and allows the user to specify a custom namespace. I would prefer it if Postgres allowed a wider range of advisory locks though!

2
Post #25
phoffer

phoffer

Is there any estimate of when the Dashboard will be available? Not trying to be pushy, only curious as that is such an awesome feature/addon.

I really like how you’ve designed this from a user (/developer) point of view, and will definitely be adding it to the app I’m currently building. I’m currently using Que (and like it) but I do have some use cases for a DB backed job queue which will necessitate switching.

2
Post #26
sorentwo

sorentwo OP

Oban Core Team

Right, there are some major limitations to advisory locks. Part of the reason I used bigint primary keys instead of guid was so that they could double as lock values. For int you can use the pg_try_advisory_lock(key1 int, key2 int) variant and essentially namespace the lock. That doesn’t work with bigint though, in that case we only have pg_try_advisory_lock(key bigint). Initially I used the two int variety with the table oid and truncated the id to 32 bits, but it seemed messy so I ditched it for a simple bigint lock.

That’s a nice solution, definitely something I should look into implementing! For Oban it was critical that jobs use bigint instead of int, or at least have a mechanism to grow beyond 32 bits.

1
Post #27
sorentwo

sorentwo OP

Oban Core Team

Sorry, somehow I missed that. I’ll update the table accordingly.

Good to know. That’s an important use-case that I misinterpreted based on this statement in the README:

One thing to be aware of is that if you restart your application (e.g. because you deployed) then all running jobs on that node will be exited. For this reason it is probably sensible not to make your jobs take an extremely long time.

I’ll update the table for this one too :+1:

The bit about “job cancelling” refers to cancelling jobs that are currently running more so than deleting them. Though it is funny, with a Postgres backed queue it is really easy to remove a job. In a Redis backed queue it is a major pain!

1
Post #28
benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Makes sense, just trying to understand the role the advisory locks play. Is there a writeup within the repo I’m missing?

1
Post #29
sorentwo

sorentwo OP

Oban Core Team

Ah, now I follow. I don’t think there is a comprehensive description of how the advisory locks are used within the repo. It is strewn between the query module and some of the integration tests.

Essentially advisory locks are used to keep track of which jobs are actively executing and which ones are in the executing state, but actually belong to a dead node.

Earlier in this thread I described it in some detail. I’ll get that worked into the README or primary module docs.

3
Post #30