One of the biggest advantages comes when you start thinking about them in terms of transactions. Transactional guarantees are really useful here: guarantee that a message will be written to the queue if the transaction commits successfully, and guarantee that a message will NOT be written to the queue otherwise.
https://brandur.org/job-drain describes a great pattern for achieving that using PostgreSQL transactions.
>you're big enough to experience this failure fairly often IMO
Please explain how? You would either have to suffer from frequent network connectivity issues that affects only your db and not your queue, or your process must be mysteriously dying in the microseconds between those 2 operations. Either of those cases are not something I would consider things that happen "fairly often," even if you were processing trillions of messages per day.
In my experience, the vast majority of message processing failures happen at the worker level.
You’re guaranteed to break the invariant sooner or later so you end up with all the usual complexity of keeping stuff in sync.
Edit>> I see you edited your post after I responded. None of those scenarios qualify as "fairly often."