Repository navigation
Fix Sidekiq 7+ and the install migration (3.6.3) - #46
Conversation
Enqueue the runner class name and a string-keyed application_version, and resolve the worker mixin through Patches.sidekiq_job_module so Sidekiq before 6.3 still gets Sidekiq::Worker.
Move the Sidekiq-dependent specs under spec/sidekiq/ so they can be excluded, and assert the optional-integration contract from both sides.
It inherited from a bare ActiveRecord::Migration, which Rails has refused since 5.0, so patches:install:migrations then db:migrate failed. [5.0] is accepted by every Rails from 5.0 to 8.1, so no minimum moves.
defined?(:Rails) tests a symbol literal, so outside Rails this raised NameError instead of returning nil.
lib/generators/patches.rb wrote to app/db/ from a template that does not exist, and Rails' generator lookup only loads *_generator.rb.
Replaces the single Ruby 2.7 cell with 14 Ruby 3.0-3.4 / Rails 7.1-8.1 combinations and a leg per Sidekiq state, moves rails, sqlite3, sidekiq and concurrent-ruby to the Gemfile so they can be varied, and drops development dependencies no spec referenced. No runtime constraint changes.
Migrating the shared database left Patches::Patch with column information for a table it had just dropped, so whichever spec the random order ran next failed with MissingAttributeError. Runs in-memory instead.
There was a problem hiding this comment.
🟡 Changes recommended
Three critical compatibility regressions and one moderate Sidekiq argument issue remain unresolved.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Fixes Sidekiq 7+ compatibility and Rails migration behavior for release 3.6.3 while expanding tests and CI coverage.
Changes:
- Adds JSON-safe Sidekiq arguments and version-compatible mixins.
- Fixes migration and non-Rails path handling.
- Modernizes testing, dependencies, documentation, and CI.
File summaries
| File | Review |
|---|---|
spec/tenant_runner_spec.rb |
Updates inline tenant-runner coverage. |
spec/spec_helper.rb |
Configures strict Sidekiq arguments. |
spec/sidekiq/worker_spec.rb |
Tests strict-argument enqueueing. |
spec/sidekiq/tenant_worker_spec.rb |
Updates retry expectations. |
spec/sidekiq/tenant_runner_spec.rb |
Tests parallel tenant enqueueing. |
spec/sidekiq/sidekiq_job_spec.rb |
Tests Sidekiq mixin selection. |
spec/sidekiq_optional_spec.rb |
Tests optional Sidekiq integration. |
spec/patches_spec.rb |
Tests operation without Rails. |
spec/migration_spec.rb |
Tests migration loading and execution. |
README.md |
Documents compatibility and local testing. |
patches.gemspec |
Prunes development dependencies. |
lib/tasks/patches.rake |
Enqueues JSON-native runner data. |
lib/patches/worker.rb |
Critical (2 votes): transform_keys breaks supported older Ruby/Rails stacks. |
lib/patches/version.rb |
Bumps the version to 3.6.3. |
lib/patches/tenant_worker.rb |
Critical (2 votes): transform_keys breaks supported older Ruby/Rails stacks. |
lib/patches/tenant_runner.rb |
Moderate (1 vote): explicit Pathname values remain incompatible with strict Sidekiq arguments. |
lib/patches/sidekiq_job.rb |
Selects the available Sidekiq mixin. |
lib/patches.rb |
Fixes Rails detection and conditional Sidekiq loading. |
lib/generators/patches.rb |
Removes an obsolete generator. |
Gemfile |
Adds environment-selectable test dependencies. |
db/migrate/201506011700_create_patch.rb |
Critical (2 votes): versioned migration inheritance fails on still-supported Rails 3.2/4.2. |
CHANGELOG.md |
Documents release 3.6.3. |
.github/workflows/specs.yml |
Expands Rails, Ruby, and Sidekiq CI coverage. |
Review details
- Files reviewed: 23/23 changed files
- Comments generated: 4
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Hash#transform_keys is Ruby 2.5+ and ActiveSupport only added its own in Rails 4.0, so it excluded stacks the gemspec still permits. stringify_keys predates both.
Patches.default_path returns a Pathname, which Sidekiq 7+ rejects as a non-JSON argument. Reachable only by passing path: explicitly.
There was a problem hiding this comment.
🔵 Needs a closer look
The migration breaks fresh installs on still-permitted Rails 3.2/4.2 versions and needs a compatible superclass fallback.
Review details
Suppressed comments (3)
README.md:66
- These environment assignments apply only to
bundle install(including the assignment before the&&command), not to the subsequentbundle exec. The absent recipe therefore reevaluates the Gemfile with Sidekiq enabled and can reject the lockfile, while the strict-off recipe never setsSIDEKIQ_STRICT_ARGS=falseduring the specs. Repeat the variables for the test command or export them first.
SIDEKIQ_VERSION=none bundle install
bundle exec rspec --exclude-pattern "sidekiq/**/*_spec.rb"
SIDEKIQ_VERSION="~> 7.0" SIDEKIQ_STRICT_ARGS=false bundle install && bundle exec rspec
README.md:75
- The pins here are scoped only to
bundle install; the next command reevaluates the Gemfile with its defaultrails >= 7.1, so Bundler sees a changed dependency and the Rails 6.1 recipe cannot run as written. Apply the same variables tobundle exec rspec(or export them).
RAILS_VERSION="~> 6.1.0" SQLITE3_VERSION="~> 1.4" CONCURRENT_RUBY_VERSION="< 1.3.5" bundle install
bundle exec rspec
db/migrate/201506011700_create_patch.rb:1
- This creates an effective Rails 5 floor for fresh installs even though the gemspec still permits Rails 3.2+ and the release notes say older Rails are not blocked. Rails 3.2/4.2 do not implement
ActiveRecord::Migration.[], so loading the copied migration now fails before creating the table. Keep the versioned parent on modern Rails while falling back to the former parent where the version API is unavailable.
class CreatePatch < ActiveRecord::Migration[5.0]
- Files reviewed: 23/23 changed files
- Comments generated: 0 new
- Review effort level: Balanced
Prefixing only bundle install left bundle exec to re-resolve the Gemfile with its defaults, so the documented recipes ran a different Rails, or ran with Sidekiq present while claiming it was absent.
|
Reviewed the three suppressed comments from the latest pass. Two were correct and are fixed in af99c0c; the third is a restatement of a decision recorded above.
Each recipe now uses an
CI was never affected — job-level I also added a line about deleting
|
Publishes to RubyGems on a v* tag via OIDC trusted publishing, matching rdytech/superset-client.
Mirrors rdytech/superset-client. The README pointed people at rake release, which would now publish the gem from a workstation and make the workflow's own run fail, so it links to RELEASING.md instead.
The worker specs pass already-correct arguments, so reverting runner.name to runner in patches:run left the whole suite green. Asserts on the call rather than the enqueued job, which Sidekiq JSON-normalises.
Verified locally against Rails 7.2, 8.0 and 8.1. Ruby 4.0 is newer than all three of those Rails releases, so the cells record that Patches works on it rather than that Rails claims support for it.
|

0 New Issues
0 Fixed Issues
0 Accepted Issues
Bug fixes plus test and tooling work, deliberately scoped so that anything which
installed 3.6.2 installs this.
git diff develop -- patches.gemspecis commentsonly: no runtime constraint changes, no API changes, nothing removed from the
public interface.
One qualification, recorded under Known issues in the CHANGELOG: because the
install migration now declares
ActiveRecord::Migration[5.0], a freshinstall on Rails 4.2 or earlier needs
patches_patchescreated by hand. Thefile it replaces could not be loaded by any Rails from 5.0 on, so this trades an
install that was impossible on every version CI verifies for one that is
unlikely. Existing installs copied the migration into the host application long
ago and are unaffected.
First step of a staged modernisation — declaring
activerecord, boundingslack-notifierand adding deprecations belong in 3.7.0; raising minimums in4.0.0.
Fixes
Sidekiq 7+ rejected our job arguments. Strict argument checking, on by
default from Sidekiq 7, refused what the workers enqueued:
patches:runpassedthe runner class object and
application_versionused a symbol key, soenqueueing raised
The task now enqueues
runner.nameand the key is a string. The serialisedpayload is byte-identical to 3.6.2's — verified by putting both call styles
through Sidekiq's JSON encoding:
The class already reached Redis as
"Patches::Runner"and the key as"application_version", so in-flight jobs and rolling deploys mixing old andnew workers are unaffected. The workers also normalise params keys to strings so
the version-mismatch retry can't re-enqueue symbol keys.
Older Sidekiq keeps working. Rather than switching to
Sidekiq::Joboutright, the workers resolve their mixin through
Patches.sidekiq_job_module,which prefers
Sidekiq::Job(the name Sidekiq has used since 6.3) and fallsback to
Sidekiq::Worker. A spec covers both branches.The install migration never worked on modern Rails. It inherited from a bare
ActiveRecord::Migration, which Rails has refused since 5.0 with "Directlyinheriting from ActiveRecord::Migration is not supported", so
rake patches:install:migrations && rake db:migratefailed on every Rails since— the table must have been created by hand. It now declares
ActiveRecord::Migration[5.0]. That version deliberately: Rails still ships theV4_2-onward compatibility shims, confirmed on 6.1, 7.2 and 8.1, so the fixwidens compatibility without raising a floor.
spec/migration_spec.rbcovers a file that shipped with no coverage at all.
Patches.default_pathguarded ondefined?(:Rails), which tests a symbolliteral and is always truthy, so outside Rails it raised
NameErrorinstead ofreturning nil.
Removed
lib/generators/patches.rb: a dead duplicate of the patch generator, writing toapp/db/from a template that does not exist. Rails' generator lookup onlyloads
*_generator.rb, so it was unreachable and not public interface.CI
One Ruby 2.7 cell becomes 14 Ruby/Rails combinations (Ruby 3.0–3.4 against Rails
7.1–8.1), plus a leg per Sidekiq state: absent, 6.5, and 7.x/8.x with strict
arguments both on and off.
Ruby 2.7 and Rails 6.1/7.0 are left out as long past upstream support. Nothing
blocks them — no constraint moved — and README.md documents how to check such a
combination locally.
Development dependencies are pruned to those actually used (six were referenced
by no spec, and
rspec-railswas never required), and rails, sqlite3, sidekiqand concurrent-ruby move to the Gemfile. CI varies rails and sidekiq through it;
the sqlite3 and concurrent-ruby knobs are for reproducing a pre-7.1 Rails
locally, which no cell now covers.
The stale
sidekiq ~> 3.4.1pin is what hid this incompatibility from CI, andit also held
jsonat~> 1.0. Dropping it closes the three open Dependabotalerts (1 high, 2 moderate), all of which are that pin; Sidekiq was only ever
a development dependency, so no consumer was exposed through Patches.
The SonarQube analysis moves into its own job rather than trailing the spec run,
so coverage is now measured on Ruby 3.2 instead of 2.7. SimpleCov is untouched
here and the report path stays
coverage/.resultset.json; replacing that withthe JSON formatter is a separate change.
Verification
All 14 cells and all 6 Sidekiq legs green — 63 examples, 48 with Sidekiq absent
— so every combination this release claims has been run. Rails 6.1 and 7.0 were
also run once on Ruby 3.0, green, to support the statement that they still work
while going untested.
CI found a bug that the local sweep did not. The first run failed 6 of 22
checks with
ActiveModel::MissingAttributeErrorinspec/patch_spec.rb. Thescattered pattern — Ruby 3.2/7.1 passing while 3.1/7.1 failed, Sidekiq 8.0
failing only with strict arguments off — was order-dependence rather than a
version problem: the new
migration_specdropped and recreated the sharedpatches_patchestable, leavingPatches::Patchholding column information fora table that no longer existed, so whichever spec the random seed ran next blew
up.
The local sweep missed it because every one of those cells reused a
test.dbleft from an earlier run, while CI always creates it fresh — and only on that
path does the drop corrupt the model's column cache. Deleting
test.dbreproduced it immediately.
a604482fixes it by running the migration against a throwaway in-memorydatabase, so the shared one is never touched, restoring the connection and
resetting column information afterwards. Verified across 10 seeds with a fresh
database each time, plus a direct before/after on the seed that failed:
Worth carrying forward:
rm -f test.dbbelongs in the local verificationrecipe, and the suite would be better off not depending on a persistent sqlite
file at all —
database_cleanersat in the gemspec for years without ever beingwired up. A candidate for the 3.7.0 tooling work.
Review round
Copilot raised four inline comments; each is answered in its thread.
transform_keysexcluded older stacks (worker.rb,tenant_worker.rb) —valid. Fixed in
8097dbc: ActiveSupport'sstringify_keyspredates bothHash#transform_keys(Ruby 2.5) and ActiveSupport's own (Rails 4.0), so itexcludes nothing the gemspec permits. Also added an explicit
require "active_support/core_ext/hash/keys"rather than relying on the hostapplication having loaded it.
Pathnamepath is rejected by strict argument checking(
tenant_runner.rb) — valid. Fixed ina3ac178by passingpath && path.to_s, with a spec that fails without the change. Unreachablethrough documented usage — the rake task always calls
runner.newwith noarguments — but
TenantRunner.new(path:)is a public constructor.documented rather than fixed (
b5d02ca). A conditional superclass wasconsidered and rejected: it would bend the shipped migration around versions
no test exercises, and Rails 3.2/4.2 cannot run on any Ruby this project
builds against, so the branch would be permanently unverified. Raising the
railtiesfloor to match reality is queued for 4.0.0.Reviewing
Eleven commits, one idea each; the three bug fixes are separate. Note that the
first five carry the old gemspec pins, since the tooling change lands in
cde1f1d— they're runnable on Ruby 2.7 but not on a modern Ruby, where Sidekiq3.x won't install.
a604482fixes the CI failure described above, and the last threecommits are the review responses — all kept as their own commits rather than
amends, since the branch was already under review.
🤖 Generated with Claude Code