Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
d24bcd7
Refactor: Reorganize tests and move ActiveJob to Rails-compliant paths
mensfeld Nov 4, 2025
94930e5
changes sync
mensfeld Dec 3, 2025
9b3c37e
version syncs
mensfeld Dec 3, 2025
391e568
use-case specs
mensfeld Dec 3, 2025
19eeb27
fix req
mensfeld Dec 3, 2025
8732cd5
remarks
mensfeld Dec 4, 2025
6924043
Skip integration tests when dependencies unavailable
mensfeld Dec 4, 2025
410ff38
Fix bundler env inheritance in integration tests
mensfeld Dec 4, 2025
786957a
Use isolated bundle path for integration tests
mensfeld Dec 4, 2025
fd34310
Show bundle install output for skipped tests
mensfeld Dec 4, 2025
746212a
Create isolated bundle config for integration tests
mensfeld Dec 4, 2025
100c6f6
Use ruby -rbundler/setup to avoid bundle exec config issues
mensfeld Dec 4, 2025
97e11eb
Use bundle standalone for isolated integration test deps
mensfeld Dec 4, 2025
e85bf38
Clear RUBYOPT to avoid bundler auto-load in CI
mensfeld Dec 4, 2025
a0ec431
Use Bundler.with_unbundled_env for isolated bundle install
mensfeld Dec 4, 2025
f95ab6b
remarks
mensfeld Dec 10, 2025
af9aa3f
cleanup
mensfeld Dec 10, 2025
c131641
remarks
mensfeld Dec 10, 2025
39c0fdb
Add enqueue_all for bulk ActiveJob and new integration tests
mensfeld Dec 10, 2025
2b4b27e
Remove shebang and redundant requires from integration specs
mensfeld Dec 10, 2025
1ac9227
Only load ActiveJob in specs that need it
mensfeld Dec 10, 2025
460fa70
Remove double blank lines from integration specs
mensfeld Dec 10, 2025
9189edd
Add enqueue_all to CHANGELOG
mensfeld Dec 10, 2025
c9cc123
Add active_job/extensions require to ActiveJob specs
mensfeld Dec 10, 2025
a062a2a
Add DataCollector (DT) for thread-safe test data collection
mensfeld Dec 10, 2025
bd828b0
Use DT pattern in all applicable integration specs
mensfeld Dec 10, 2025
6a61766
Add CurrentAttributes persistence support
mensfeld Dec 10, 2025
79458a5
Expand CurrentAttributes integration tests
mensfeld Dec 10, 2025
54a06c5
Fix middleware_chain spec: use &block instead of yield in define_method
mensfeld Dec 10, 2025
bfd41c4
Simplify integration test setup
mensfeld Dec 10, 2025
b4e3558
Add E2E tests for ActiveJob retry/discard and custom attributes
mensfeld Dec 10, 2025
5a7d930
Add setup_active_job helper and bin/clean_localstack cleanup script
mensfeld Dec 10, 2025
6c3c8d4
Remove unnecessary error handling from clean_localstack
mensfeld Dec 10, 2025
e0c26f9
Remove obvious comments and fix assertion style in integration specs
mensfeld Dec 10, 2025
ce21b79
Reorganize integration specs into granular single-scenario files
mensfeld Dec 10, 2025
c3defc9
Remove redundant minimumReleaseAge rule for github-actions
mensfeld Dec 10, 2025
0857089
Merge main branch and add Rails specs CI job
mensfeld Dec 10, 2025
c49dbe7
Remove rails_specs job that requires missing gemfiles
mensfeld Dec 10, 2025
b0ea3ad
Split CI into separate Specs and Integrations jobs
mensfeld Dec 10, 2025
e1c7812
Address PR review comments
mensfeld Dec 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 24 additions & 42 deletions .github/workflows/specs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,82 +2,64 @@ name: Specs
on:
- push
- pull_request
permissions:
contents: read
jobs:
all_specs:
name: All Specs
specs:
name: Specs
strategy:
matrix:
ruby: ['3.1', '3.2', '3.3', '3.4']
gemfile: ['Gemfile']
ruby: ['3.2', '3.3', '3.4']
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1

- name: Start LocalStack
run: docker compose up -d

- name: Wait for LocalStack
run: |
timeout 30s bash -c '
until curl -s http://localhost:4566/_localstack/health | grep -q "\"sqs\": \"available\""; do
echo "Waiting for LocalStack..."
sleep 2
done
'

- uses: ruby/setup-ruby@8aeb6ff8030dd539317f8e1769a044873b56ea71 # v1.268.0
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true

- name: Run specs
run: bundle exec rake spec
env:
BUNDLE_GEMFILE: ${{ matrix.gemfile }}

- name: Run integration specs
run: bundle exec rake spec:integration
env:
BUNDLE_GEMFILE: ${{ matrix.gemfile }}

rails_specs:
name: Rails Specs
integrations:
name: Integrations
strategy:
matrix:
rails: ['7.2', '8.0', '8.1']
include:
- rails: '7.2'
ruby: '3.2'
gemfile: gemfiles/rails_7_2.gemfile
- rails: '8.0'
ruby: '3.3'
gemfile: gemfiles/rails_8_0.gemfile
- rails: '8.1'
ruby: '3.4'
gemfile: gemfiles/rails_8_1.gemfile
ruby: ['3.2', '3.3', '3.4']
runs-on: ubuntu-latest
env:
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
steps:
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1

- name: Start LocalStack
run: docker compose up -d

- name: Wait for LocalStack
run: |
timeout 30s bash -c '
until curl -s http://localhost:4566/_localstack/health | grep -q "\"sqs\": \"available\""; do
echo "Waiting for LocalStack..."
sleep 2
done
'

- uses: ruby/setup-ruby@8aeb6ff8030dd539317f8e1769a044873b56ea71 # v1.268.0
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true

- name: Run Rails specs
run: bundle exec rake spec:rails
- name: Run integration specs
run: bundle exec rake spec:integration

ci-success:
name: CI Success
runs-on: ubuntu-latest
if: always()
needs:
- all_specs
- rails_specs
- specs
- integrations
steps:
- name: Check all jobs passed
if: |
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,6 @@ shoryuken.yml
rubocop.html
.byebug_history
.localstack
spec/integration/**/Gemfile.lock
spec/integration/**/vendor/
spec/integration/**/.bundle/
1 change: 1 addition & 0 deletions .rspec
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
--color
--require spec_helper
--exclude-pattern "spec/integration/**/*"
25 changes: 22 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,35 @@
## [7.0.0] - Unreleased
- Enhancement: Add `enqueue_all` for bulk ActiveJob enqueuing (Rails 7.1+)
- Implements efficient bulk enqueuing using SQS `send_message_batch` API
- Called by `ActiveJob.perform_all_later` for batching multiple jobs
- Batches jobs in groups of 10 (SQS limit) per queue
- Groups jobs by queue name for efficient multi-queue handling

- Enhancement: Add ActiveJob Continuations support (Rails 8.1+)
- Implements `stopping?` method in ActiveJob adapters to signal graceful shutdown
- Enables jobs to checkpoint progress and resume after interruption
- Handles past timestamps correctly (SQS treats negative delays as immediate delivery)
- Tracks shutdown state in Launcher via `stopping?` flag
- Leverages existing Shoryuken shutdown lifecycle (stop/stop! methods)
- Includes comprehensive integration tests with continuable jobs
- See Rails PR #55127 for more details on ActiveJob Continuations

- Enhancement: Add CurrentAttributes persistence support
- Enables Rails `ActiveSupport::CurrentAttributes` to flow from enqueue to job execution
- Automatically serializes current attributes into job payload when enqueuing
- Restores attributes before job execution and resets them afterward
- Supports multiple CurrentAttributes classes
- Based on Sidekiq's approach using `ActiveJob::Arguments` for serialization
- Usage: `require 'shoryuken/active_job/current_attributes'` and
`Shoryuken::ActiveJob::CurrentAttributes.persist('MyApp::Current')`

- Breaking: Drop support for Ruby 3.1 (EOL March 2025)
- Minimum required Ruby version is now 3.2.0
- Supported Ruby versions: 3.2, 3.3, 3.4
- Users on Ruby 3.1 should upgrade or remain on Shoryuken 6.x

- Breaking: Remove support for Rails versions older than 7.2
- Rails 7.0 and 7.1 have reached end-of-life and are no longer supported
- Supported versions: Rails 7.2, 8.0, and 8.1
- Rails 7.0 and 7.1 have reached end-of-life (April 2025) and are no longer supported
- Supported Rails versions: 7.2, 8.0, and 8.1
- Users on older Rails versions should upgrade or remain on Shoryuken 6.x

- Enhancement: Replace Concurrent::AtomicFixnum with pure Ruby AtomicCounter
Expand Down
1 change: 0 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ group :test do
end

group :development do
gem 'appraisal', git: 'https://github.com/thoughtbot/appraisal.git'
gem 'pry-byebug'
gem 'rubocop'
end
14 changes: 4 additions & 10 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,13 @@ $stdout.sync = true

begin
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec) do |t|
t.exclude_pattern = 'spec/integration/**/*_spec.rb'
end
RSpec::Core::RakeTask.new(:spec)

namespace :spec do
desc 'Run Rails specs only'
RSpec::Core::RakeTask.new(:rails) do |t|
t.pattern = 'spec/shoryuken/{environment_loader_spec,extensions/active_job_*}.rb'
end

desc 'Run integration specs only'
RSpec::Core::RakeTask.new(:integration) do |t|
t.pattern = 'spec/integration/**/*_spec.rb'
task :integration do
puts "Running integration tests..."
system('./bin/integrations') || exit(1)
end
end
rescue LoadError
Expand Down
52 changes: 52 additions & 0 deletions bin/clean_localstack
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

# Removes all integration test SQS queues from LocalStack
#
# Useful when having a long-running LocalStack instance that cannot be fully
# restarted between test runs. All integration test queues use the 'it-' prefix,
# making them easy to identify and remove.
#
# Usage:
# bin/clean_localstack

require 'aws-sdk-sqs'

THREADS_COUNT = 3

sqs = Aws::SQS::Client.new(
region: 'us-east-1',
endpoint: 'http://localhost:4566',
access_key_id: 'fake',
secret_access_key: 'fake'
)

# Find all queues with 'it-' prefix
response = sqs.list_queues(queue_name_prefix: 'it-')
queues_for_removal = response.queue_urls || []

if queues_for_removal.empty?
puts "No integration test queues found (prefix: it-)"
exit 0
end

puts "Found #{queues_for_removal.size} queues to remove"

queue = SizedQueue.new(THREADS_COUNT)

threads = Array.new(THREADS_COUNT) do
Thread.new do
while (queue_url = queue.pop)
queue_name = queue_url.split('/').last
puts "Removing queue: #{queue_name}"
sqs.delete_queue(queue_url: queue_url)
end
end
end

queues_for_removal.each { |url| queue << url }

queue.close
threads.each(&:join)

puts "Cleanup complete"
Loading