Encoding Elixir terms to oban jobs table

My understanding is that with open source Oban, jobs args are always encoded to JSON before being saved to the database.

With Oban Pro, if we use Structured Jobs, we can pass say Elixir structs and they will be safely encoded and decoded when saved or retrieved from the database.

I assume there is a downside to this though, perhaps that persisted jobs that haven’t run yet might fail after a code deploy that modified those structs? And extra database bloat?

By extension, this question relates to Recorded Jobs as well.

Thanks.

This is the case for regardless of whether it’s OSS or Pro; the args and meta columns are jsonb and data is always stored as valid JSON.

This is correct. The term type allows you to pass any valid term, including structs, into the database. There’s always potential for failure if you reference a data type that doesn’t exist. That’s a common caveat for passing a pid or ref, but I’m not sure if it applies to structs because the validation happens at compile time.

Encoded data is still stored as a JSON string, but it’s encoded for UTF-8 compatibility. That means there’s ~30% bloat compared to non-term values.

Our general advice is to use resource ids and fetch records in the job rather than using full structs in args when possible. It’s definitely smaller, easier to query for in the dashboard, and it ensures the job will have fresh data on retry.


Aside–all term data stored by Oban uses the [:safe] decode mode by default, to avoid possible attacks.

2 Likes

One thing to note is when you use term, e.g a struct over a map or an atom over a string, is that you can’t read the value with your human eyes.

1 Like

I am not entirely sure what you are trying to achieve, but you should probably avoid putting too big of payloads, whether it’s JSON or a Elixir struct on the argument of the Oban job. You will get punished quite severely in terms of performance if you do so. Trust me, I’ve been there.

What you want is a job that takes one or several arguments that are IDs of some records in the database, and the job itself will pull the data required for it to complete.

This is much more performant and will not slow down your queue as much as putting bigger payloads on the args.

7 Likes