Skip to content

Document Solid Queue batch jobs in the Active Job guide [ci-skip] - #1

Open
jpcamara wants to merge 30 commits into
mainfrom
solid-queue-batch-jobs-guide
Open

Document Solid Queue batch jobs in the Active Job guide [ci-skip]#1
jpcamara wants to merge 30 commits into
mainfrom
solid-queue-batch-jobs-guide

Conversation

@jpcamara

@jpcamara jpcamara commented Aug 22, 2026

Copy link
Copy Markdown
Owner

Motivation / Background

Solid Queue 1.7 added support for grouping jobs into batches (rails/solid_queue#142), but the Active Job Basics guide doesn't mention them. Since the guide has a substantial "Default Backend: Solid Queue" section covering the backend's other features (concurrency controls, recurring tasks, transactional integrity), batches belong alongside them.

Detail

Adds a ### Batch Jobs subsection after Recurring Tasks, following the structure of the neighboring sections: a motivating use case (importing a file row by row, then notifying), the three callbacks and when each fires, a worked example with an "In the above example" walkthrough mirroring the Concurrency Controls section, a NOTE on the migration applications that installed Solid Queue before 1.7 need, and a closing link to the Solid Queue documentation for deeper details.

Every claim was verified against the released solid_queue 1.7.0 gem. Documentation only, no behavior change. mdl passes with the repository's style configuration.

Checklist

Before submitting the PR make sure the following are checked:

  • This Pull Request is related to one change. Unrelated changes should be opened in separate PRs.
  • Commit message has a detailed description of what changed and why. If this PR fixes a related issue include it in the commit message.
  • Tests are added or updated if you fix a bug or add a feature. (n/a — documentation only)
  • CHANGELOG files are updated for the changed libraries. (n/a — guides changes don't update CHANGELOGs)

bensheldon and others added 3 commits August 21, 2026 15:12
`average` casts the result to `BigDecimal` for integer and decimal
columns, not to `Float`. Float is only returned for float columns, which
the "given column's type" case already covers.
…skip]

The dirty tracking values in the example are those of a persisted record,
but `u` is built with `User.new` and never saved, so `color_was` is `nil`
and `color_change` is `[nil, 'green']`. Create the record so that the
documented values hold.
@github-actions github-actions Bot added the docs label Aug 22, 2026
byroot and others added 26 commits August 23, 2026 00:46
Further improve Reflextion#extensions
`content.rb` and `markdown_conversion.rb` declare `# :markup: markdown`,
but their doc comments used RDoc's `+text+` and `<tt>` markup, which
renders literally under that directive.

Use backticks.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013fCL4kH4H9z8CiKWtPVke4
`Content#to_markdown` built the `<action-text-markdown>` wrapper inline,
so the tag name lived in `Content` while `MarkdownConversion` matched the
same literal in two private constants.

Extract the wrapper into `MarkdownConversion.render_attachment`, next to
a shared `RAW_MARKDOWN_TAG_NAME` the constants now use. No behavior
change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013fCL4kH4H9z8CiKWtPVke4
`Content#to_markdown` wraps attachment Markdown in
`<action-text-markdown>` so the converter emits it without escaping, but
the converter could not tell that element from one a user typed into a
rich text body. A body holding a literal `<action-text-markdown>`
therefore had its text emitted verbatim, bypassing the URI scheme check
in `MarkdownConversion#markdown_link`.

Unwrap the element in `Content.fragment_by_canonicalizing_content`,
which runs for every `Content` built from outside the framework,
including bodies loaded from the database. Attachment markup is added
afterwards on a `canonicalize: false` `Content`, so it still passes
through.

`fragment_by_unwrapping_raw_markdown_tags` sits next to
`render_attachment` and the tag name they share, so both sides of that
boundary are in one file. The order they run in is what makes the fix
work, so a test asserts it by name rather than leaving it to the
attachment tests that would incidentally fail.

`Fragment#to_markdown` and `MarkdownConversion.node_to_markdown` neither
canonicalize nor render attachments, and are documented as unsafe for
untrusted content.

ref: https://hackerone.com/reports/3727743

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LPp9kjB67z8k27f9uv4dq7
…turn-type

Fix the documented return type of AVG calculations
…c-example

Fix the Active Record Store dirty tracking documentation example
`fetch_indexes` builds `optional_columns` before it looks at `tables`, and
`supports_expression_index?` asks for `database_version`, so `indexes([])`
opens the connection just to read nothing. Return early like the SQLite
reader already does.

This fails `SchemaStatementsTest#test_an_empty_list_reads_nothing` whenever
it runs right after a test that re-establishes the connection, which CI hits
often:

https://buildkite.com/rails/rails/builds/132802/canvas?sid=01a0320e-c18f-4c26-b4d3-84069b6971fb&tab=output#01a0320e-c1f8-4cab-b837-86aa84688c4b/L11493
…th-an-empty-list

Don't touch the connection in MySQL's `fetch_indexes` for an empty list
`@extension` (singular) is undefined, and `nil.frozen?` is always true,
causing unnecessary `dup` calls.
…-typo

Fix typo in Reflection initializer
The pattern of duping a Hash to later append a key to it
isn't ideal because if the original Hash was full, its
copy will be too and it will need to be reallocated on insertion.

By using the `{ **base, new_key: 1 }` pattern, we allow Ruby to
directly allocate a hash of the right size, at least on Ruby 4.1.

Ref: ruby/ruby#18344

This callsite has been identified as a common source of such
reallocations in the ruby-bench suite (lobsters and shipit).
url_for: use Hash splat to append keys
…pe-issue

Allow `translate`'s `scope:` argument to resolve relative i18n keys with leading period
Strip user-supplied `<action-text-markdown>` while canonicalizing
The block form only works for blocking query execution, and we want
QueryIntent to be more flexible. This also makes for a cleaner break:
the current version had already deprecated the historical log(sql, ..)
form; now the method is deprecated wholesale without needing to check
any parameter types.
We've previously relied on the caller 1) being inside a rescue, and 2)
immediately raising the return value, to set the cause. In anticipation
of callers prefering to retain the translated exception for later use,
let's instead make sure we return a fully-populated exception object,
setting the cause at the same time we set the backtrace.
Instead of directly setting the raw_result on the intent, and
immediately raising on error, we now involve the intent in both.

Where a result is available, the intent is given a chance to act on that
information (updating related internal state, owning the log-finish).

In the case of an error, that is also delivered to the intent, where it
will be stored, and only raised when a caller asks for the result. (All
existing callers ask immediately after executing the intent, so this
doesn't practically defer any exceptions right now -- no change in
existing behaviour.)
For safety, ensure that all intents that have started do get finished,
even if the caller somehow forgets about them.
Warnings are part of a query's delivered outcome: store warnings on the
intent, and run the configured warning action when the caller observes
that outcome, so async execution doesn't raise on the worker's behalf or
mask the query error.
Some storage representations compare through database expressions that
do not belong in Ruby casting or serialization. Allow Active Record
types to define a symmetric comparison expression for hash predicates
while retaining ordinary bind serialization.
A join compares stored values, so each side needs its own type's
expression.
Query predicate expressions for Active Record types, take 2
Drive result delivery through QueryIntent
@jpcamara
jpcamara force-pushed the solid-queue-batch-jobs-guide branch from 7f17624 to da1c4de Compare August 24, 2026 21:22
@jpcamara jpcamara changed the title Document Solid Queue batch jobs in the Active Job guide Document Solid Queue batch jobs in the Active Job guide [ci-skip] Aug 24, 2026
Solid Queue 1.7 added batches, but the Active Job Basics guide did not
cover them. Add a Batch Jobs section under Default Backend: Solid Queue,
following the shape of the neighboring sections: motivate the feature
with a row-by-row import, list the three callbacks and when each runs,
walk through the example the way the concurrency section walks through
its options, and close with a NOTE on the migration applications that
installed Solid Queue before 1.7 need, plus a link to the Solid Queue
documentation for the deeper details.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants