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
end

Available Callbacks

Service Callbacks

Callback
When it runs
Arguments

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

Callback
When it runs
Arguments

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)

Note the difference between on_step_failure and on_step_crash:

  • on_step_failure is called when a step adds errors (similar to on_service_failure)

  • on_step_crash is called when a step raises an exception

When a step crashes (raises an exception), after_step_run is NOT called.

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:

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.

Next: Testing

Last updated