Shoryuken Documentation

repository·main·Indexed 24 days ago

https://github.com/ruby-shoryuken/shoryuken

A high-performance, thread-based AWS SQS message processor for Ruby. It provides a simple interface for defining workers, integrates as an ActiveJob adapter for Rails, and includes a CLI for SQS queue management tasks such as purging, creating, deleting, and moving messages.

Tokens
4.5K
Snippets
6
Records
36
Agent score
79%

What's inside Shoryuken

  1. Handle FIFO queue limitations with ActiveJob

    main

    Shoryuken's ActiveJob adapter has specific constraints when working with SQS FIFO queues:

    1. No Per-Message Delays: FIFO queues do not support per-message delays. If you attempt to use enqueue_at (which calculates a delay) on a FIFO queue, the adapter will raise Shoryuken::Errors::FifoDelayNotSupportedError.
      • Workaround: When using ActiveJob's retry_on with FIFO queues, set wait: 0 to avoid triggering a delay.
    2. Message Deduplication: By default, if Shoryuken.active_job_fifo_message_deduplication? is true, the adapter generates a message_deduplication_id based on a SHA256 hash of the job body (excluding job_id and enqueued_at).
      • Workaround: If you need distinct enqueues of the same job class and arguments to NOT be deduplicated, set Shoryuken.active_job_fifo_message_deduplication = false.
  2. Implement a custom polling strategy using BaseStrategy

    main

    If you need to control how Shoryuken selects which queue to poll next, you can implement a custom polling strategy by subclassing Shoryuken::Polling::BaseStrategy.

    To create a functional strategy, you must override the following abstract methods:

    • next_queue: Returns a QueueConfiguration object representing the next queue to poll, or nil if no queues are available.
    • messages_found(queue, count): Invoked after polling a queue. Use this to adjust polling behavior (e.g., pausing empty queues or adjusting weights) based on the number of messages retrieved.
    • active_queues: Returns an array of queues that are currently active and available for polling.

    Additionally, you can optionally override message_processed(queue) to perform actions after a message has been successfully processed.

    class CustomStrategy < Shoryuken::Polling::BaseStrategy
      def initialize(queues)
        @queues = queues
      end
    
      def next_queue
        # Return next queue to poll
        @queues.sample
      end
    
      def messages_found(queue, count)
        # Handle result of polling
        logger.info "Found #{count} messages in #{queue}"
      end
    
      def active_queues
        # Return list of active queues
        @queues
      end
    end
  3. Enable automatic visibility timeout extension in workers

    main

    Shoryuken provides the Shoryuken::Middleware::Server::AutoExtendVisibility middleware to prevent messages from becoming visible to other consumers while they are still being processed.

    To use this feature, your worker class must implement and return true for auto_visibility_timeout?.

    Important Constraints:

    • Batch Workers: Auto-extension is not supported for batch workers. If a batch is detected, the middleware will log a warning and skip extension.
    • Queue Timeout Requirements: The SQS queue's visibility timeout must be long enough to allow for a scheduled extension. If the queue's visibility timeout is too short (specifically, if it is $\le 0$ or results in a non-positive interval based on EXTEND_UPFRONT_SECONDS), the middleware will log a warning and will not extend the visibility.
    • Mechanism: The middleware uses a TimerTask to call change_visibility on the SQS message at regular intervals before the current timeout expires.
  4. Signal handling in Shoryuken

    main

    The Shoryuken::Runner traps several Unix signals to manage the worker lifecycle. Understanding these signals allows you to control the server behavior without killing the process abruptly:

    • USR1: Triggers a soft shutdown. The server will stop and exit.
    • TSTP: Triggers a terminal stop. The server will stop accepting new work but may continue processing current tasks.
    • TTIN: Triggers a thread backtrace dump. The runner will log the backtraces of all active threads to the logger, which is useful for debugging hung processes.
    • TERM or INT: Triggers a standard shutdown sequence.
  5. Use the WeightedRoundRobin polling strategy

    main

    The Shoryuken::Polling::WeightedRoundRobin strategy processes queues in a round-robin order where queue weights are determined by the number of times a queue name is repeated in the initialization array.

    Key Behaviors:

    • Weighting: A queue appearing multiple times in the input array will be polled more frequently.
    • Auto-Pausing: If a queue is polled and no messages are found, it is temporarily paused.
    • Auto-Unpausing: Paused queues are automatically re-added to the rotation after a specified delay has passed.
    • Dynamic Weight Adjustment: If messages are found, the strategy attempts to increase the queue's weight (up to its initial configured weight) by adding it back to the rotation more frequently.
  6. Implement exponential backoff retry for workers

    main

    Shoryuken provides the ExponentialBackoffRetry server middleware to automatically adjust the SQS visibility timeout when a job fails. This allows for increasing delays between retries.

    To use this, your worker class must:

    1. Implement a class method exponential_backoff? that returns true.
    2. Provide Shoryuken options via get_shoryuken_options containing a retry_intervals key.

    Retry Interval Configuration The retry_intervals option can be configured in two ways:

    • An Array of Integers: The middleware uses the index corresponding to the current attempt (based on SQS ApproximateReceiveCount). If the number of attempts exceeds the array size, it uses the last element in the array.
    • A Proc/Callable: A object that responds to .call(attempts), where attempts is the current attempt number.

    Important Behaviors:

    • Non-retryable Exceptions: If an exception is listed in the non_retryable_exceptions option, the middleware will re-raise it immediately without applying a backoff. This allows other middleware (like NonRetryableException) to handle the message (e.g., by deleting it).
    • Batch Workers: Exponential backoff is not supported for batch workers; if a batch is processed, the middleware will simply yield and allow the error to propagate normally.
    • Visibility Timeout Cap: The calculated visibility timeout is automatically capped to ensure it does not exceed the SQS maximum (approximately 43,200 seconds minus processing time).
  7. Use the ShoryukenConcurrentSendAdapter for ActiveJob

    main

    The ShoryukenConcurrentSendAdapter is an ActiveJob adapter that sends messages asynchronously (non-blocking). It allows you to provide custom handlers to react to successful enqueues or enqueue failures, which is useful for monitoring (e.g., via StatsD) or logging.

    To use it, initialize the adapter with a success_handler and an error_handler (both expected to be Proc objects) and assign it to your ActiveJob configuration.

    success_handler = ->(response, job, options) { StatsD.increment("#{job.class.name}.success") }
    error_handler = ->(err, job, options) { StatsD.increment("#{job.class.name}.failure") }
    
    adapter = ActiveJob::QueueAdapters::ShoryukenConcurrentSendAdapter.new(success_handler, error_handler)
    config.active_job.queue_adapter = adapter
  8. Persist Rails CurrentAttributes across Shoryuken jobs

    main

    To ensure request-scoped context (such as current_user, tenant, or locale) flows from the code that enqueues an ActiveJob to the job's execution, use Shoryuken::ActiveJob::CurrentAttributes.persist.

    This integration automatically serializes the attributes of your ActiveSupport::CurrentAttributes classes into the SQS message body during enqueueing and restores them before the job executes.

    Note on Cleanup: Unlike Sidekiq, which relies on the Rails executor to reset attributes, Shoryuken performs a blanket reset of all registered CurrentAttributes classes after every job execution to prevent thread-local data leakage in the worker thread pool.

    require 'shoryuken/active_job/current_attributes'
    
    # Register a single class
    Shoryuken::ActiveJob::CurrentAttributes.persist('MyApp::Current')
    
    # Or register multiple classes
    Shoryuken::ActiveJob::CurrentAttributes.persist('MyApp::Current', 'MyApp::RequestContext')
  9. Configure the SQS CLI endpoint

    main
    When using the sqs command namespace, you can specify a custom SQS endpoint URL using the --endpoint or -e flag. This is useful for connecting to local SQS emulators (like LocalStack) or specific AWS regions. If not provided, it defaults to the value of the SHORYUKEN_SQS_ENDPOINT environment variable.
  10. Configure retry_intervals for exponential backoff

    main

    When using the ExponentialBackoffRetry middleware, you can define how long the message should remain invisible in SQS before being retried using the retry_intervals key in your worker's Shoryuken options.

    Option 1: Array of Integers

    Provide an array where each element represents the delay (in seconds) for a specific attempt number.

    • Attempt 1 uses array[0]
    • Attempt 2 uses array[1]
    • If attempts exceed the array length, the last element is used repeatedly.

    Option 2: Callable (Proc)

    Provide an object that responds to .call(attempts). The attempts argument is the current ApproximateReceiveCount from SQS.

    Note: These options must be returned by the worker's get_shoryuken_options method.