Class: Sidekiq::NormalizeArgsMiddleware
- Inherits:
-
Object
- Object
- Sidekiq::NormalizeArgsMiddleware
- Defined in:
- lib/sidekiq/normalize_args_middleware.rb
Overview
Middleware to normalize hash arguments to use string keys consistently.
Sidekiq serializes job arguments to JSON, which always produces string keys.
However, the lock digest for sidekiq-unique-jobs is computed BEFORE serialization,
using the original Ruby hash. This means:
perform_async(delivery_id: 123) # symbol key
perform_async("delivery_id" => 123) # string key
Could produce different lock digests, causing duplicate jobs to slip through.
This middleware normalizes hash arguments to string keys on both client and server:
- Client: Ensures consistent lock digest computation
- Server: Ensures workers receive consistent hash format
Workers can still use symbol access via with_indifferent_access, but this
removes the ambiguity at the source.
THIS IS THE SINGLE NORMALIZATION PATH FOR ENQUEUED JOBS. If a worker is only
ever reached via perform_async/perform_in/perform_at, do NOT re-normalize
inside it — no options.symbolize_keys, no options.with_indifferent_access,
no options['x'] || options[:x] pairs. #perform already receives a
HashWithIndifferentAccess, so options[:force] and options['force'] both
resolve. A local copy of this logic reads as though the middleware is absent,
which is how PublicationVisionWorker got misdiagnosed as silently dropping
force: in 2026-07 (it never was).
IT DOES NOT COVER DIRECT Worker.new.perform(...) CALLS — no client push, no
server chain, so #perform gets exactly the Hash the caller built. Symbol keys
still read fine there; STRING keys do not. Fix the CALLER, not the worker: a
test hand-writing 'force' => true is asserting a shape production never
delivers, so pass symbol keys exactly like an enqueue site would. Direct
callers live in tests, rake tasks, and the dev-mode branches in
ItemsController#auto_translate_*.
Two more cases sit OUTSIDE the server chain:
self.lock_args(args)runs client-side, before the server half — read
string keys there (see DeliveryShipConfirmWorker).- callers computing a digest by hand
(SidekiqUniqueJobsJidLookup.active_jid_for_args) or searching stored args
(BackgroundJobStatus.search) must pass.stringify_keysto match what
the Client half wrote.
Covered by test/lib/sidekiq/normalize_args_middleware_test.rb, which also
guards that both halves stay registered in config/initializers/sidekiq.rb.