Free forever, no credit card.Get Started for Free →
← All posts
November 11, 2026 · 6 min read

Does GoodJob Remember Between Runs? Jobs Are Stored in Postgres. The Next Job Still Starts With Only Its Arguments.

Does GoodJob Remember Between Runs? Jobs Are Stored in Postgres. The Next Job Still Starts With Only Its Arguments. GoodJob is a background job backend for Ruby on Rails that runs on PostgreSQL. It plugs into Active Job, stores every job in the same Postgres database the application already uses, and claims work with advisory locks instead of a separate queue service. For a Rails team whose jobs do AI work on a schedule, that raises a practical question: when the same job runs again tomorrow, d

Does GoodJob Remember Between Runs? Jobs Are Stored in Postgres. The Next Job Still Starts With Only Its Arguments.

GoodJob is a background job backend for Ruby on Rails that runs on PostgreSQL. It plugs into Active Job, stores every job in the same Postgres database the application already uses, and claims work with advisory locks instead of a separate queue service. For a Rails team whose jobs do AI work on a schedule, that raises a practical question: when the same job runs again tomorrow, does it know anything about today's run? No. GoodJob stores the job, its serialized arguments, and a record of each execution. The next job still starts with only the arguments it was enqueued with. What the last run found, decided, or already handled is not passed along.

A job is a row in good_jobs, written at enqueue time

Calling perform_later inserts a row into the good_jobs table, inside the same database transaction as the code that enqueued it, so the job and the change that caused it commit together or roll back together. That row holds the job class, the queue name, the priority, the scheduled time for delayed work, and the arguments, serialized at enqueue time. Records passed as arguments travel as GlobalID references, so the job loads a fresh copy of the record when it runs. A worker then claims the row with a Postgres advisory lock, wakes quickly through LISTEN/NOTIFY when new work lands, and runs perform with exactly those arguments.

Read that row closely and its scope becomes clear. Every field answers an execution question. Which class should run. On which queue. With which arguments. At what time. How many attempts have been made. None of the fields answers a work question: which accounts did yesterday's run already review, which exception did a person approve last week, or which conclusion should today's run build on instead of rediscovering it? The row knows how to start the job. It does not carry a briefing from the job before it.

The arguments are also fixed in advance by the code that calls perform_later. They can carry context chosen beforehand, such as an account id or a date range. They are not a channel where a finished job automatically writes what it learned for the next job to pick up. If the enqueueing code does not already know a fact at enqueue time, the next job does not learn it from GoodJob.

Executions record attempts, not findings

GoodJob keeps more than the queue itself. Each attempt is recorded as an execution, with its timing and, when something goes wrong, the error that ended it. Finished jobs can be preserved so the built-in dashboard can show what ran, what succeeded, and what failed, and a cleanup task prunes old preserved jobs. A team can inspect a failed job there, retry it, or discard it.

None of that history is assembled into a briefing. GoodJob does not take yesterday's executions, merge them with the runs before them, and hand the result to tomorrow's job as part of its arguments. It does not search past jobs on the same queue and summarize what they established. A job that wants yesterday's result has to query the job and execution tables itself, know what it is looking for, and interpret raw rows and error text itself, all outside the normal flow. In that flow, each job arrives on its own.

Failure follows the same boundary. Active Job retries re-enqueue the job with a delay, and the retry receives the same class and the same arguments as the earlier attempt. That is the right design for a transient error, such as a rate limit or a dropped connection. It is not a way to tell the retry what the first attempt managed to finish before it failed, or what a person decided after reading the error. A discarded job is simply gone from the work queue, and nothing it learned travels to any other job.

Cron remembers when, not what was learned

GoodJob also handles recurring work directly, with cron-style schedules configured in the application. A cron entry names a job class, a schedule, and the arguments to enqueue each time, so a report, a sync, or a review can fire every day or every hour without outside code enqueueing it. That makes the timing durable, even across deploys and restarts.

A cron entry changes nothing about knowledge. Every firing enqueues a fresh job from the stored entry, with the same stored arguments. If Monday's run discovered that a customer had already been contacted, that a report had already been sent, or that a data source had changed its format, Tuesday's cron job does not receive that discovery unless some outside system rewrote the configured arguments or the job loads the discovery from somewhere else. The cron entry is an excellent clock. A clock is not a memory of the work.

The missing layer is shared memory, and it sits beside the queue

None of this is a reason to replace the queue. GoodJob does the job it promises: transactional enqueueing in Postgres, advisory-lock claiming, retries, cron schedules, batches, concurrency controls, and a dashboard, all without adding Redis or another service to run. The gap appears when the job is an AI agent step in a recurring automation, because that step needs a past, not just a trigger. It needs to start each run already knowing what previous runs established, across every tool in the workflow, not only inside one application's database tables.

That past is what Vilix AI provides as a shared memory layer. Vilix AI is cloud-hosted, so there is zero infrastructure to run or maintain: no extra database to provision, no memory service to deploy next to the worker. The same memory is available everywhere over MCP, so the GoodJob worker, the chat tool used to review its output, and every other connected agent read and write one shared memory instead of separate local notes. And Vilix AI stores full conversation history, not just extracted facts, so a run can revisit what was actually said and decided, in context, rather than working from a compressed summary.

In practice the split is simple. GoodJob decides when work happens and runs it reliably inside the Rails application. Before the job acts, it checks Vilix AI for what earlier runs already found, which items are already handled, and which corrections a person already gave. After the job finishes, it saves its findings back, so the next firing, on any schedule and in any tool, starts briefed instead of blank.

Getting started carries no commitment. Vilix AI has a free plan that is free forever, and a 7-day Pro trial with no credit card required. Data stays under the operator's control, with the ability to export everything or delete it anytime. A queue that stores jobs cleanly in Postgres is a strong foundation for scheduled work. Adding one shared memory beside it is what turns a job that merely runs every day into an agent that remembers every day.

Get Started for Free

Persistent memory across ChatGPT, Claude, and the AI tools you already use in Vilix AI.

Get Started for Free

Free forever, no credit card.

Keep reading
Does Google Cloud Tasks Remember Between Runs? A Task Lives for Up to 31 Days. The Next Run Still Starts With Only Its Payload.

Does Google Cloud Tasks Remember Between Runs? A Task Lives for Up to 31 Days. The Next Run Still Starts With Only Its Payload. Google Cloud Tasks remembers the task, exactly as it was created, until the task is done or too old. A task sits in its queue with its payload, its target, and its schedule, and it stays there through retries until it succeeds, exhausts its attempts, or reaches 31 days of age. That is dependable delivery memory. What Cloud Tasks never keeps is anything the handler lear

Does Azure Event Hubs Remember Between Runs? Events Stay in the Partitioned Log for Up to 90 Days. The Next Run Still Starts With Only Its Event.

Does Azure Event Hubs Remember Between Runs? Events Stay in the Partitioned Log for Up to 90 Days. The Next Run Still Starts With Only Its Event. Azure Event Hubs remembers the event, in full, in the log. An event hub is an append-only log that stores events, producers add new events to the end of a partition, and those events stay there for the whole retention period whether anyone read them or not. That is real retention, and it is stronger than a queue that deletes on delivery. What Event Hu

Does Apache RocketMQ Remember Between Runs? Messages Stay in the CommitLog for Days. The Next Run Still Starts With Only Its Message.

Does Apache RocketMQ Remember Between Runs? Messages Stay in the CommitLog for Days. The Next Run Still Starts With Only Its Message. Apache RocketMQ remembers the message, in full, on disk. A broker writes every message it receives into a shared physical log, keeps it for the whole storage duration whether anyone consumed it or not, and lets a consumer go back and read it again inside that window. That is real retention, and it is stronger than a queue that deletes on delivery. What RocketMQ n