Skip to content

Support bound Redis job dispatch with a semaphore - #12

Open
jbaxendale-ut wants to merge 1 commit into
socketry:mainfrom
user-interviews:fix/semaphore-dispatcher-default
Open

Support bound Redis job dispatch with a semaphore#12
jbaxendale-ut wants to merge 1 commit into
socketry:mainfrom
user-interviews:fix/semaphore-dispatcher-default

Conversation

@jbaxendale-ut

Copy link
Copy Markdown

Add support for using an Async::Semaphore to bound Redis job processing, which we needed to support rate limiting an external API (ultimately reserving interview capacity for multiple users)

When a semaphore is supplied, a permit is held from the blocking fetch through job completion and only one blocking fetch is in flight. The server also retains active workers for cancellation, releases permits during shutdown, and stops dispatching if dequeue or heartbeat recovery has failed rather than entering a reconnect/logging loop.

Disclaimer: developed with the help of Codex as I was investigating latency issues in an LLM-moderated interview flow in our application. Let me know if this seems in appropriate, but wanted to offer my changes (running in production now) upstream see also socketry/async-job-adapter-active_job#29

Hosts that need a bounded worker can apply a shared concurrency limit without changing queue semantics or allowing jobs to accumulate outside the limit.

Types of Changes

  • Bug fix.
  • New feature.

Contribution

A long-running application may need a Redis worker to share a bounded capacity with other work without changing the existing task-parent behavior. Previously the server had no semaphore-aware dispatcher lifecycle or permit ownership model.

Accept an Async::Semaphore parent, hold a permit from blocking fetch through job completion, and keep only one blocking fetch in flight. The default task-parent behavior remains unchanged. A single dispatcher launcher preserves the required Async lifecycle in each mode, and a single processing cleanup path releases permits exactly once.

On a failed fetch or heartbeat, stop dispatching rather than spin, retain active workers for cancellation, and release remaining permits on shutdown. This gives any Redis-backed AsyncJob host a predictable concurrency boundary without coupling the processor to application-specific scheduling.

Signed-off-by: Jeff Baxendale <jbaxendale@usertesting.com>
@jbaxendale-ut
jbaxendale-ut force-pushed the fix/semaphore-dispatcher-default branch from 8c1729d to 8bc63a6 Compare September 3, 2026 20:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant