Use when integrating background jobs, async jobs, or background processing in Hanami 2.x — including Sidekiq integration, GoodJob worker setup, or any job queue configuration. Sets up background job providers, injects job-adapter dependencies into Hanami actions, creates job-triggering actions, and generates corresponding RSpec tests.
Installation
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Use when integrating background jobs, async jobs, or background processing in Hanami 2.x — including Sidekiq integration, GoodJob worker setup, or any job queue configuration. Sets up background job providers, injects job-adapter dependencies into Hanami actions, creates job-triggering actions, and generates corresponding RSpec tests.
Handoff condition: Adapter accessible via Deps["jobs.client"]
# config/providers/background_jobs.rbHanami.app.register_provider(:background_jobs) do
start dorequire"sidekiq"Sidekiq.configure_client do |config|
config.redis = { url: target[:settings].redis_url }
end
register("jobs.client", Sidekiq::Client)
endend
Validation: Verify registration with MyApp::App["jobs.client"] in a Hanami console or container lookup spec. It should return Sidekiq::Client without raising Dry::Container::Error.
[Inject into Action] — Load skill: inject-dependencies
Inject job adapter into Action
Handoff condition: Adapter injectable
classCreate < MyApp::ActionincludeDeps["jobs.client", "repos.user_repo"]
end
[Enqueue from Action] — Load skill: create-action
Define job class
Enqueue job from Action after successful operation
Handle enqueue failures gracefully — rescue enqueue errors and log them; do not crash the Action
Handoff condition: Jobs are enqueued and executed
# app/jobs/welcome_email.rbmoduleMyAppmoduleJobsclassWelcomeEmailincludeSidekiq::Workerdefperform(user_id)
user = user_repo.by_id(user_id).one
mailer.deliver(to: user.email, subject:"Welcome!")
endendendend
classCreate < MyApp::Actiondefhandle(request, response)
result = create_user.call(request.params[:user])
case result
inSuccess(user)
jobs.client.push("class" => "MyApp::Jobs::WelcomeEmail", "args" => [user.id])
response.status = 201inFailure(error)
response.status = 422endrescue => e
Hanami.logger.error("Job enqueue failed: #{e.message}")
response.status = 201# Still succeed; enqueue failure is non-fatalendend
Validation: Confirm jobs are being enqueued by checking the Sidekiq dashboard (/sidekiq) or inspecting the Redis queue directly (Sidekiq::Queue.new.size). In tests, use Sidekiq::Testing.fake! and assert on MyApp::Jobs::WelcomeEmail.jobs.
[Write Job Specs] — Load skill: write-action-spec
Test job class in isolation with stubbed dependencies
Test that Action enqueues the job
Handoff condition: Job specs pass
# spec/unit/my_app/jobs/welcome_email_spec.rbRSpec.describe MyApp::Jobs::WelcomeEmaildo
subject(:job) { described_class.new }
let(:user_repo) { instance_double(MyApp::Repos::UserRepo) }
let(:mailer) { instance_double(MyApp::Mailers::Welcome) }
let(:user) { instance_double(MyApp::Entities::User, id:42, email:"user@example.com") }
before do
allow(user_repo).to receive(:by_id).with(42).and_return(double(one: user))
allow(mailer).to receive(:deliver)
job.instance_variable_set(:@user_repo, user_repo)
job.instance_variable_set(:@mailer, mailer)
end
it "delivers a welcome email to the user"do
job.perform(42)
expect(mailer).to have_received(:deliver).with(to:"user@example.com", subject:"Welcome!")
endend# spec/requests/users/create_spec.rb (enqueue assertion)RSpec.describe "POST /users"do
before { Sidekiq::Testing.fake! }
after { Sidekiq::Worker.clear_all }
it "enqueues a WelcomeEmail job on success"do
expect {
post "/users", params: { user: { name:"Alice", email:"alice@example.com" } }
}.to change(MyApp::Jobs::WelcomeEmail.jobs, :size).by(1)
expect(last_response.status).to eq(201)
endend
Common Pitfalls
Synchronous execution of deferrable work — Use jobs for emails, notifications, exports, or anything that can be deferred.
Missing enqueue error handling — Rescue enqueue errors and log them. Do not crash the Action on transient queue failures.
Direct container access in jobs — Inject dependencies via DI container; do not access the container directly inside jobs.
Passing complex objects as job arguments — Jobs serialize to JSON. Pass IDs or simple scalar data, never Ruby objects.
Missing job tests — Always test the job class in isolation and verify the Action enqueues correctly.
Jobs not registered in DI container — The job adapter client must be registered as a provider before it can be injected.