Callbacks
Callbacks are hooks that allow you to run custom code at specific points during service and step execution. They're perfect for logging, benchmarking, auditing, and other cross-cutting concerns.
TL;DR
Define callbacks using DSL methods like
before_service_run,after_step_run, etc.Use symbols (method names) or procs/lambdas
Callbacks are inherited from parent classes
Around callbacks wrap execution and must yield
class User::Charge < ApplicationService
before_service_run :log_start
after_service_run :log_end
on_service_failure :notify_admin
around_step_run :benchmark_step
step :authorize
step :charge
private
def log_start(service)
Rails.logger.info "Starting #{service.class.name}"
end
def log_end(service)
Rails.logger.info "Finished #{service.class.name}"
end
def notify_admin(service)
AdminMailer.service_failed(service).deliver_later
end
def benchmark_step(service, step_name)
start = Time.current
yield
duration = Time.current - start
Rails.logger.info "Step #{step_name} took #{duration}s"
end
endAvailable Callbacks
Service Callbacks
before_service_run
Before the service starts executing steps
(service)
after_service_run
After the service completes (success or failure)
(service)
around_service_run
Wraps the entire service execution
(service, &block)
on_service_success
After service completes without errors
(service)
on_service_failure
After service completes with errors
(service)
Step Callbacks
before_step_run
Before each step executes
(service, step_name)
after_step_run
After each step completes (success or failure)
(service, step_name)
around_step_run
Wraps each step execution
(service, step_name, &block)
on_step_success
After step completes without errors
(service, step_name)
on_step_failure
When step produces errors
(service, step_name)
on_step_crash
When step raises an exception
(service, step_name, exception)
Defining Callbacks
Using Symbols (Method Names)
The most common way to define callbacks is using symbols that reference instance methods:
Using Procs/Lambdas
For simple callbacks, you can use inline procs:
Around Callbacks
Around callbacks wrap execution and must call yield to continue:
Around Callbacks with Procs
When using procs for around callbacks, the block is passed as the last argument:
Forgetting to call yield (or block.call for procs) in around callbacks will prevent the service/step from executing!
Multiple Callbacks
You can define multiple callbacks of the same type. They execute in the order they're defined:
Multiple Around Callbacks
Multiple around callbacks are nested, with the first one wrapping the second:
Callback Inheritance
Callbacks are inherited from parent classes. Child class callbacks run after parent callbacks:
Deep Inheritance
Callbacks accumulate through the inheritance chain:
Execution Order
Service Callbacks Order
Step Callbacks Order (for each step)
Normal execution (no exception):
Exception during step:
Use Cases
Logging
Benchmarking
Error Tracking
Audit Trail
Database Instrumentation
What's Next?
Learn about testing your services, including how to test callbacks.
Last updated