AL+

Language: RO (română) EN (English)

Email us: paul@alplustech.com

A resumable job needs more than a progress cursor

Active Job intermediate attributes need a serialization contract of their own. Separate values needed on resume from cursors and long-term application records.

Citiți articolul în română

Knowing where a background job stopped does not tell you everything it needs to continue. A later step can depend on a value produced earlier. If the worker resumes without that value, a correct progress cursor is insufficient. Resumable jobs need an explicit serialization contract for intermediate values, separate from both progress and the application's long-term records.

The Rails roundup of 8 May 2026 discussed ActiveJob::Attributes: typed attributes serialized with the job and restored when it resumes. The design addresses a specific gap between remembering a step and remembering what that step produced. It does not, by itself, make external actions happen exactly once.

Progress and intermediate values answer different questions

A cursor describes progress through work. An intermediate attribute holds something later work needs. Keeping these roles distinct makes a continuation easier to explain. Otherwise the implementation can appear resumable while silently depending on values that only existed in the previous worker's memory.

The pull request gives the motivation directly. Its author described multi-step jobs needing temporary intermediate data without storing that data long term on Active Record models. The example uses values such as a payment token and a billing profile identifier. Those are source examples, rather than evidence of an AL+ payment integration or a recommendation to put arbitrary secrets into job storage.

The author also considered storing a step's return value automatically and preferred explicit attributes. That choice gives reviewers a place to see which values are meant to survive serialization. An ordinary local variable and a declared persistent attribute communicate different expectations about the lifetime of data. The distinction helps when reading a job without having its entire execution in memory.

The chronology is precise. The proposal opened on 19 April and merged into main on 5 May 2026. The 8 May roundup discussed that change; it was not an 8 May stable release of the feature. An application decision still needs evidence about the installed implementation before depending on the API. A development announcement does not establish that evidence.

Serialization defines what survives

The value needed later must have a representation that survives the job's serialization and restoration. A type declaration helps express intent, but the design question remains what the restored value means to the next step. The persisted representation should be part of the job's contract, rather than an accidental consequence of how a particular Ruby object looked during one execution.

This contract also has a lifetime. A value needed between steps does not automatically belong in the durable domain model. Conversely, calling something intermediate does not mean it can be discarded while work still depends on it. The team needs to distinguish the end of the job's need for the value from the end of the business record's usefulness.

For maintenance, that distinction matters when code changes while jobs may still resume. A new implementation can read an older serialized value. The review should ask what assumptions the later step makes and whether the stored representation still meets them. The feature's existence does not remove the application's responsibility for the meaning of its own attributes.

The same reasoning limits what should be stored. A job attribute is a persistence location, not merely an in-memory convenience. Values placed there should be chosen deliberately with regard to who needs them and how long they remain relevant. The source's example illustrates a dependency between steps; it does not establish a universal retention or confidentiality policy for job data.

A saved attribute does not coordinate every external effect

Suppose a step requests work from an external service and then the job is interrupted around the point at which progress and intermediate state are recorded. The application still needs to reason about what the external service accepted. Restoring a job attribute does not retroactively place the service and the job storage inside one atomic transaction. This is a conceptual failure boundary, not a reported experiment.

Exactly-once claims are therefore too broad for this feature. A continuation can preserve data needed on resume without proving that an external operation was performed once and only once. The workflow needs its own way to reconcile the external result and any repeated attempt. Keeping that requirement separate avoids assigning a serialization feature a guarantee it never established.

This is also why a job's progress should not be mistaken for the whole business history. The job tracks its execution needs. A product may need a separate account of what happened that people can inspect after execution ends. Those records serve different readers and can require different lifetimes.

Ordinary records may serve the product better

The strongest counterargument is to store workflow state in ordinary application records when humans need to inspect or intervene in the process. A value that support staff must explain, or that remains meaningful after the job finishes, may belong there. Keeping it only inside serialized job data can make the operational model harder to understand.

That does not make intermediate attributes redundant. They fit values whose role is genuinely limited to continuing execution. Ordinary records fit information with an application-level identity and a reason to remain available. The decision should follow the readers and lifetime of the data, rather than a preference to minimize tables or attribute declarations.

In custom software development, ask for a workflow description that names progress, intermediate values and durable records separately. For each value, identify its consumer and what restoration must preserve. Then review external effects as their own coordination problem. A resumable job becomes understandable when the team can explain both where it resumes and what it carries into the next step.