PATTERN Cited by 2 sources
Feature-flagged job enqueue rejection¶
A deploy-less kill-switch for async-job classes: install a client middleware on the async-job framework that, on every enqueue, derives a per-class feature-flag name from the worker class and checks a general feature-flag system; if the flag is on, short-circuit the enqueue so the job never reaches the job store.
The pattern¶
# pseudocode — see Sidekiq Ruby example below
class JobKillMiddleware
def call(worker_class, job, queue, store)
# convention-driven flag name
flag_name = "disable_#{underscore(worker_class.to_s)}"
return false if feature_flag_enabled?(flag_name)
yield # otherwise pass through
end
end
Wiring: install the middleware on the client chain of the job framework (the chain that runs when code enqueues a job), not the server chain (which runs when workers execute a job). Enqueue-side interception prevents backlog accumulation.
Four load-bearing design choices¶
- Client middleware (producer side), not server middleware (consumer side). Prevents enqueue; no jobs pile up in the store to be drained later. Disabling a job class while other classes in the same queue keep running is just the flag being per-class, not per-queue.
- Naming convention derives the flag name from the class
name. No registry, no catalog, no manual wiring. The
flag
disable_invoice_jobdisablesInvoiceJobwithout anyone having to configure that mapping. Operators can always answer "what's the flag for this job?" by running the class-name transform. - General feature-flag system as the config channel. No bespoke kill-switch infrastructure. Whatever feature- flag system the application already uses for release engineering provides the distribution channel, the storage, and the invocation surface. One fewer subsystem to build and operate.
- Short-circuit by returning falsy. The job-framework
middleware contract is "return falsy to stop the job from
progressing." No exception; no retry storm; no entry in
the store. The producer call (
Worker.perform_async(...)) just returnsfalse/nilas if the job were silently dropped, which it is — intentionally.
Canonical Sidekiq implementation (PlanetScale, 2022)¶
From sources/2026-04-21-planetscale-how-to-kill-sidekiq-jobs-in-ruby-on-rails:
module SidekiqMiddleware
class SidekiqJobsFlipper
def call(worker_class, job, queue, redis_pool)
# return false/nil to stop the job from going to redis
klass = worker_class.to_s
if Flipper.enabled?("disable_#{klass.underscore.to_sym}")
return false
end
yield
end
end
end
Wired in config/initializers/sidekiq.rb:
Sidekiq.configure_server do |config|
config.client_middleware do |chain|
chain.add(SidekiqMiddleware::SidekiqJobsFlipper)
end
end
Operator invocation: Flipper.enable("disable_invoice_job")
from a Rails console. Reverse: Flipper.disable(...).
When to use it¶
- Production is running, some job class is misbehaving, and you need to stop enqueueing more of that class now without a deploy.
- An incoming deploy is known to make a specific job class unsafe; flip the flag off pre-deploy, deploy, un-flip post-verification.
- Running a one-off data backfill that shouldn't trigger side-effect jobs; flag off the side-effect-job class, run the backfill, flag on.
- Canary rollout by job class: disable a new job class in production until ready, then enable.
When not to use it¶
- When jobs are already in the queue. This pattern gates future enqueues; it doesn't drain existing jobs. Combine with a manual queue flush for incident response.
- When you need argument-level granularity. Cannot
disable
InvoiceJobforaccount_id=42specifically; all-or-nothing per class. Build a flag-check insideperforminstead. - When you need an audit trail of attempts. The middleware silently drops enqueues; there's no record of the attempt unless you add explicit logging.
- When callers depend on
perform_async's job-id return value. Middleware returningfalsemakes the caller seefalseinstead of a job-id string — this may break callers that use the job-id for tracking.
Relationship to other patterns¶
- Global feature killswitch — same shape at the request-hot-path altitude. Cloudflare's global kill-switches are module-level; this pattern is async-job-class-level.
- Client- middleware interception — the enforcement-point concept this pattern rides on.
- Deploy-less operational lever — the class of control this is a member of.
- Feature flag — the substrate.
Seen in¶
- sources/2026-04-21-planetscale-how-to-kill-sidekiq-jobs-in-ruby-on-rails —
canonical wiki instance. PlanetScale's application-
tier Rails backend installs
SidekiqJobsFlipperon the Sidekiq client middleware chain, keyed bydisable_<classname>Flipper flags, for deploy-less per-class job suspension in production. - sources/2026-04-21-planetscale-how-we-made-planetscales-background-jobs-self-healing — canonical composition-with-scheduler instance. The same Flipper-gated middleware is used to disable scheduler jobs during an incident: "This has come in useful during an incident where we've wanted control over a specific job type." Scheduler jobs are themselves Sidekiq jobs, so subject to the same deploy-less operational lever as any other job. Shows the pattern operating at two altitudes simultaneously in the same system — disable a work job or disable the scheduler that enqueues it.