CrackedRuby logo

CrackedRuby

Rails Integration

Overview

Rails integration in Ruby encompasses the mechanisms and patterns that allow Ruby applications to interact with Rails framework components, middleware stack, and ecosystem tools. Ruby provides multiple integration points through Rack compatibility, Rails engines, generators, and the Rails application lifecycle.

The primary integration occurs through the Rails::Application class, which serves as the central configuration hub and bootstrapping mechanism. Ruby applications integrate with Rails through several key interfaces: the Rack specification for HTTP request handling, ActiveSupport for core extensions, and the Rails autoloading system for code organization.

# Basic Rails application integration
class MyApp < Rails::Application
  config.load_defaults Rails::VERSION::STRING.to_f
  
  config.middleware.use MyCustomMiddleware
  config.autoload_paths += %W[#{config.root}/app/services]
end

Rails integration relies on three core components: the initialization process that loads configuration and sets up the environment, the middleware stack that processes HTTP requests, and the routing system that dispatches requests to appropriate handlers. Ruby applications access these components through well-defined APIs that maintain compatibility across Rails versions.

# Integration with Rails middleware stack
class ApiIntegration
  def self.setup(app)
    app.middleware.insert_before ActionDispatch::ShowExceptions, 
                                CustomAuthMiddleware
    app.middleware.use Rack::CORS do
      allow do
        origins '*'
        resource '*', headers: :any, methods: [:get, :post, :options]
      end
    end
  end
end

The Rails engine system provides the most powerful integration mechanism, allowing Ruby gems to package complete Rails functionality including models, controllers, views, and routes. Engines integrate seamlessly with the host application's autoloading and asset pipeline systems.

# Rails engine integration
module MyIntegration
  class Engine < Rails::Engine
    isolate_namespace MyIntegration
    
    config.generators do |g|
      g.test_framework :rspec
      g.fixture_replacement :factory_bot
    end
    
    initializer "my_integration.configure_middleware" do |app|
      app.middleware.use MyIntegration::AuthenticationMiddleware
    end
  end
end

Rails integration also encompasses the configuration system, which uses Ruby's metaprogramming capabilities to provide a flexible, hierarchical configuration structure. Applications access configuration through Rails.application.config and environment-specific configuration files.

Basic Usage

Rails integration begins with configuring the application class and setting up the basic middleware stack. The application class inherits from Rails::Application and defines the integration points for custom Ruby components.

# config/application.rb
class MyRailsApp < Rails::Application
  config.load_defaults 7.0
  
  # Configure custom autoload paths
  config.autoload_paths += [
    Rails.root.join('app', 'services'),
    Rails.root.join('app', 'decorators'),
    Rails.root.join('lib', 'extensions')
  ]
  
  # Custom middleware integration
  config.middleware.insert_after ActionDispatch::Flash, 
                                 CustomSessionMiddleware
  
  # Background job integration
  config.active_job.queue_adapter = :sidekiq
  config.active_job.queue_name_prefix = Rails.env
end

Integrating custom Ruby classes with Rails requires understanding the autoloading system and naming conventions. Rails uses zeitwerk for autoloading, which expects files to be named according to the constant they define.

# app/services/user_authentication_service.rb
class UserAuthenticationService
  include ActiveModel::Model
  include ActiveModel::Attributes
  
  attribute :email, :string
  attribute :password, :string
  
  validates :email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
  validates :password, length: { minimum: 8 }
  
  def authenticate!
    user = User.find_by(email: email)
    return false unless user&.authenticate(password)
    
    Rails.cache.write("user_session_#{user.id}", user.id, expires_in: 24.hours)
    user
  end
end

Controller integration follows Rails conventions while allowing custom Ruby logic to handle business operations. Controllers act as the integration layer between HTTP requests and Ruby business logic.

class Api::V1::AuthenticationController < ApplicationController
  before_action :set_authentication_service
  
  def create
    if @auth_service.valid? && (user = @auth_service.authenticate!)
      render json: { 
        user: UserSerializer.new(user),
        token: generate_jwt_token(user)
      }, status: :ok
    else
      render json: { 
        errors: @auth_service.errors.full_messages 
      }, status: :unprocessable_entity
    end
  end
  
  private
  
  def set_authentication_service
    @auth_service = UserAuthenticationService.new(auth_params)
  end
  
  def auth_params
    params.require(:authentication).permit(:email, :password)
  end
  
  def generate_jwt_token(user)
    JWT.encode(
      { user_id: user.id, exp: 24.hours.from_now.to_i },
      Rails.application.secrets.secret_key_base,
      'HS256'
    )
  end
end

Model integration combines ActiveRecord with custom Ruby modules to extend database functionality while maintaining Rails conventions for validation, callbacks, and associations.

class User < ApplicationRecord
  include Authenticatable
  include Trackable
  
  has_secure_password
  
  validates :email, presence: true, uniqueness: true
  validates :role, inclusion: { in: %w[admin user moderator] }
  
  scope :active, -> { where(active: true) }
  scope :by_role, ->(role) { where(role: role) }
  
  after_create :send_welcome_email
  after_update :track_changes, if: :saved_changes?
  
  def admin?
    role == 'admin'
  end
  
  def full_name
    "#{first_name} #{last_name}".strip
  end
  
  private
  
  def send_welcome_email
    UserMailer.welcome(self).deliver_later
  end
  
  def track_changes
    TrackingService.new(self, saved_changes).record_changes
  end
end

Background job integration connects Ruby classes with Rails' ActiveJob framework, providing a consistent interface for asynchronous processing across different queue adapters.

class DataProcessingJob < ApplicationJob
  queue_as :high_priority
  retry_on StandardError, wait: :polynomially_longer, attempts: 3
  
  def perform(user_id, data_file_path)
    user = User.find(user_id)
    processor = DataProcessor.new(data_file_path)
    
    result = processor.process do |progress|
      # Update job progress for monitoring
      Rails.logger.info "Processing: #{progress}% complete"
    end
    
    NotificationService.notify_user(user, :data_processed, result)
  rescue DataProcessor::InvalidFormatError => e
    NotificationService.notify_user(user, :processing_failed, e.message)
    raise
  end
end

Production Patterns

Production Rails integration requires careful consideration of performance, monitoring, security, and scalability patterns. Ruby applications integrate with Rails production infrastructure through standardized interfaces and configuration patterns.

Application configuration for production environments emphasizes security, performance, and monitoring integration. Production configurations typically separate concerns between application logic and infrastructure configuration.

# config/environments/production.rb
Rails.application.configure do
  config.cache_classes = true
  config.eager_load = true
  config.consider_all_requests_local = false
  config.public_file_server.enabled = false
  
  # Asset and caching configuration
  config.assets.compile = false
  config.assets.digest = true
  config.cache_store = :redis_cache_store, {
    url: ENV['REDIS_URL'],
    pool_size: ENV.fetch('RAILS_MAX_THREADS', 5).to_i,
    pool_timeout: 5,
    reconnect_attempts: 3
  }
  
  # Database connection pooling
  config.database_configuration = {
    production: {
      adapter: 'postgresql',
      pool: ENV.fetch('RAILS_MAX_THREADS', 5).to_i,
      timeout: 5000,
      checkout_timeout: 5,
      reaping_frequency: 10
    }
  }
  
  # Background job configuration
  config.active_job.queue_adapter = :sidekiq
  config.active_job.queue_name_prefix = "#{Rails.application.class.module_parent_name.downcase}_production"
  
  # Logging and monitoring
  config.log_level = :info
  config.log_tags = [:request_id, :remote_ip]
  config.logger = ActiveSupport::TaggedLogging.new(
    Syslog::Logger.new(Rails.application.class.module_parent_name.downcase)
  )
end

Health check integration provides standardized endpoints for load balancers and monitoring systems to verify application status. Health checks integrate with Rails routing and controller systems while maintaining minimal overhead.

class HealthController < ApplicationController
  skip_before_action :authenticate_user!
  
  def show
    health_status = {
      status: 'healthy',
      timestamp: Time.current.iso8601,
      version: Rails.application.config.version,
      checks: perform_health_checks
    }
    
    overall_status = health_status[:checks].all? { |check| check[:status] == 'pass' }
    status_code = overall_status ? :ok : :service_unavailable
    
    render json: health_status, status: status_code
  end
  
  private
  
  def perform_health_checks
    [
      database_check,
      redis_check,
      external_service_check
    ].compact
  end
  
  def database_check
    ActiveRecord::Base.connection.execute('SELECT 1')
    { name: 'database', status: 'pass', response_time: measure_time { ActiveRecord::Base.connection.execute('SELECT 1') } }
  rescue StandardError => e
    { name: 'database', status: 'fail', error: e.message }
  end
  
  def redis_check
    Rails.cache.redis.ping
    { name: 'redis', status: 'pass', response_time: measure_time { Rails.cache.redis.ping } }
  rescue StandardError => e
    { name: 'redis', status: 'fail', error: e.message }
  end
  
  def measure_time
    start_time = Time.current
    yield
    ((Time.current - start_time) * 1000).round(2)
  end
end

Error handling and monitoring integration captures application errors and performance metrics for production observability. Ruby applications integrate with Rails error handling through rescue handlers and instrumentation hooks.

class ApplicationController < ActionController::Base
  include ErrorHandling
  include PerformanceTracking
  
  rescue_from StandardError, with: :handle_standard_error
  rescue_from ActiveRecord::RecordNotFound, with: :handle_not_found
  rescue_from ActionController::ParameterMissing, with: :handle_parameter_missing
  
  around_action :track_performance
  before_action :set_request_id
  after_action :log_request_completion
  
  private
  
  def handle_standard_error(error)
    error_id = SecureRandom.uuid
    
    # Log error with context
    Rails.logger.error({
      error_id: error_id,
      error_class: error.class.name,
      error_message: error.message,
      backtrace: error.backtrace&.first(10),
      request_id: request.uuid,
      user_id: current_user&.id,
      params: params.except(:password, :password_confirmation).to_unsafe_h
    }.to_json)
    
    # Send to monitoring service
    ErrorTrackingService.notify(error, {
      error_id: error_id,
      user_id: current_user&.id,
      request_context: request_context
    })
    
    render json: { 
      error: 'Internal server error',
      error_id: error_id 
    }, status: :internal_server_error
  end
  
  def track_performance
    start_time = Time.current
    
    yield
    
    duration = (Time.current - start_time) * 1000
    
    MetricsService.record('request.duration', duration, {
      controller: controller_name,
      action: action_name,
      method: request.method,
      status: response.status
    })
  end
  
  def request_context
    {
      controller: controller_name,
      action: action_name,
      method: request.method,
      url: request.url,
      user_agent: request.user_agent,
      remote_ip: request.remote_ip
    }
  end
end

Security integration patterns implement authentication, authorization, and security headers through Rails middleware and controller filters. Production security requires integration between Ruby security gems and Rails security features.

class SecurityMiddleware
  def initialize(app)
    @app = app
  end
  
  def call(env)
    request = Rack::Request.new(env)
    
    # Rate limiting integration
    if rate_limited?(request)
      return rate_limit_response
    end
    
    # Security header integration
    status, headers, response = @app.call(env)
    
    headers.merge!(security_headers)
    headers['X-Request-ID'] = request.env['HTTP_X_REQUEST_ID'] || SecureRandom.uuid
    
    [status, headers, response]
  end
  
  private
  
  def rate_limited?(request)
    key = "rate_limit:#{request.ip}"
    current_count = Rails.cache.increment(key, 1, expires_in: 1.minute)
    
    if current_count == 1
      Rails.cache.write(key, 1, expires_in: 1.minute)
      false
    else
      current_count > rate_limit_threshold
    end
  end
  
  def security_headers
    {
      'X-Frame-Options' => 'DENY',
      'X-Content-Type-Options' => 'nosniff',
      'X-XSS-Protection' => '1; mode=block',
      'Strict-Transport-Security' => 'max-age=31536000; includeSubDomains',
      'Content-Security-Policy' => content_security_policy,
      'Referrer-Policy' => 'strict-origin-when-cross-origin'
    }
  end
  
  def content_security_policy
    "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https:; connect-src 'self' https:; frame-ancestors 'none';"
  end
end

Deployment integration patterns connect Ruby applications with Rails deployment tools and infrastructure automation. Production deployments require coordination between application code, database migrations, and asset compilation.

# config/deploy.rb (Capistrano integration)
set :application, 'my_rails_app'
set :repo_url, 'git@github.com:company/my_rails_app.git'
set :deploy_to, '/var/www/my_rails_app'
set :linked_files, %w[config/master.key config/database.yml]
set :linked_dirs, %w[log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system]

namespace :deploy do
  desc 'Restart application'
  task :restart do
    on roles(:app), in: :sequence, wait: 5 do
      execute :touch, release_path.join('tmp/restart.txt')
    end
  end
  
  desc 'Run database migrations'
  task :migrate do
    on roles(:db) do
      within release_path do
        with rails_env: fetch(:rails_env) do
          execute :rake, 'db:migrate'
        end
      end
    end
  end
  
  desc 'Precompile assets'
  task :precompile_assets do
    on roles(:web) do
      within release_path do
        with rails_env: fetch(:rails_env) do
          execute :rake, 'assets:precompile'
        end
      end
    end
  end
  
  after :publishing, :restart
  after :restart, :clear_cache
end

Performance & Memory

Rails integration performance depends on understanding how Ruby objects interact with Rails' autoloading, caching, and request processing systems. Performance optimization focuses on reducing object allocation, optimizing database queries, and managing memory usage across request cycles.

Database integration performance centers on connection pooling, query optimization, and caching strategies. Ruby applications must manage ActiveRecord connections efficiently to prevent connection exhaustion and query bottlenecks.

# Database connection and query optimization
class OptimizedUserService
  def self.find_users_with_posts(limit: 100)
    # Use includes to prevent N+1 queries
    users = User.includes(:posts, :profile)
                .joins(:posts)
                .select('users.*, COUNT(posts.id) as posts_count')
                .group('users.id')
                .having('COUNT(posts.id) > ?', 0)
                .limit(limit)
    
    # Preload associations efficiently
    ActiveRecord::Associations::Preloader.new.preload(
      users, 
      { posts: [:comments, :tags] }
    )
    
    users
  end
  
  def self.bulk_update_users(user_attributes)
    User.transaction do
      # Use bulk operations for better performance
      user_attributes.each_slice(1000) do |batch|
        User.upsert_all(
          batch,
          unique_by: :email,
          update_only: [:updated_at, :last_login_at]
        )
      end
    end
  end
  
  def self.cached_user_stats(user_id, expires_in: 1.hour)
    Rails.cache.fetch("user_stats:#{user_id}", expires_in: expires_in) do
      {
        posts_count: Post.where(user_id: user_id).count,
        comments_count: Comment.where(user_id: user_id).count,
        followers_count: Follow.where(followed_user_id: user_id).count,
        activity_score: calculate_activity_score(user_id)
      }
    end
  end
end

Memory management in Rails integration requires understanding object lifecycle, garbage collection patterns, and Rails' memory retention behaviors. Ruby applications must manage memory allocation patterns to prevent memory bloat in long-running processes.

class MemoryEfficientProcessor
  BATCH_SIZE = 1000
  MAX_MEMORY_MB = 500
  
  def self.process_large_dataset(file_path)
    initial_memory = memory_usage_mb
    processed_count = 0
    
    File.foreach(file_path).lazy.each_slice(BATCH_SIZE) do |batch|
      process_batch(batch)
      processed_count += batch.size
      
      # Monitor memory usage and trigger GC if needed
      current_memory = memory_usage_mb
      memory_delta = current_memory - initial_memory
      
      if memory_delta > MAX_MEMORY_MB
        Rails.logger.info "Memory threshold reached: #{memory_delta}MB, running GC"
        GC.start(full_mark: true, immediate_sweep: true)
        
        # Reset baseline after GC
        initial_memory = memory_usage_mb
      end
      
      # Yield control periodically for better concurrency
      sleep(0.001) if processed_count % 10_000 == 0
    end
    
    processed_count
  end
  
  def self.process_batch(batch)
    # Use local variables to avoid creating unnecessary object references
    results = []
    
    batch.each do |item|
      # Process items without storing references
      processed_item = transform_item(item)
      results << processed_item if processed_item.valid?
    end
    
    # Bulk insert to reduce database overhead
    if results.any?
      ProcessedItem.insert_all(results.map(&:attributes))
    end
    
    # Explicit cleanup of local variables
    results.clear
    results = nil
  end
  
  def self.memory_usage_mb
    `ps -o rss= -p #{Process.pid}`.to_i / 1024.0
  end
end

Caching integration patterns optimize Rails application performance by reducing database queries, computation overhead, and external API calls. Ruby applications integrate with Rails caching through multiple cache stores and expiration strategies.

class CachingService
  CACHE_VERSIONS = {
    user_profile: 'v2',
    post_content: 'v1',
    search_results: 'v3'
  }
  
  def self.fetch_user_profile(user_id, options = {})
    cache_key = versioned_key('user_profile', user_id)
    expires_in = options.fetch(:expires_in, 30.minutes)
    
    Rails.cache.fetch(cache_key, expires_in: expires_in, race_condition_ttl: 10.seconds) do
      profile_data = build_user_profile(user_id)
      
      # Cache warming for related data
      warm_related_caches(user_id, profile_data)
      
      profile_data
    end
  end
  
  def self.multi_fetch_posts(post_ids)
    cache_keys = post_ids.map { |id| versioned_key('post_content', id) }
    cached_posts = Rails.cache.read_multi(*cache_keys)
    
    # Identify missing posts
    missing_ids = post_ids.reject do |id|
      cached_posts.key?(versioned_key('post_content', id))
    end
    
    # Fetch missing posts from database
    if missing_ids.any?
      fresh_posts = Post.where(id: missing_ids).includes(:user, :tags)
      
      # Write missing posts to cache
      cache_entries = {}
      fresh_posts.each do |post|
        key = versioned_key('post_content', post.id)
        cache_entries[key] = serialize_post(post)
      end
      
      Rails.cache.write_multi(cache_entries, expires_in: 2.hours)
      cached_posts.merge!(cache_entries)
    end
    
    # Return posts in original order
    post_ids.map { |id| cached_posts[versioned_key('post_content', id)] }.compact
  end
  
  def self.invalidate_user_cache(user_id)
    patterns = [
      versioned_key('user_profile', user_id),
      "user_posts:#{user_id}:*",
      "user_activity:#{user_id}:*",
      "followers:#{user_id}"
    ]
    
    patterns.each do |pattern|
      if pattern.include?('*')
        # Pattern-based cache invalidation
        Redis.current.scan_each(match: pattern) { |key| Rails.cache.delete(key) }
      else
        Rails.cache.delete(pattern)
      end
    end
  end
  
  private
  
  def self.versioned_key(cache_type, identifier)
    version = CACHE_VERSIONS[cache_type.to_sym]
    "#{cache_type}:#{version}:#{identifier}"
  end
  
  def self.build_user_profile(user_id)
    user = User.find(user_id)
    {
      id: user.id,
      name: user.full_name,
      avatar_url: user.avatar.attached? ? user.avatar.url : nil,
      stats: user_statistics(user_id),
      preferences: user.preferences,
      last_activity: user.last_activity_at
    }
  end
  
  def self.warm_related_caches(user_id, profile_data)
    # Preload related data that's likely to be requested
    Rails.cache.write(
      "user_preferences:#{user_id}",
      profile_data[:preferences],
      expires_in: 1.hour
    )
  end
end

Background job performance integration focuses on queue management, job batching, and resource utilization. Ruby applications integrate with Rails ActiveJob to optimize asynchronous processing performance.

class PerformantJobProcessor < ApplicationJob
  queue_as :default
  retry_on StandardError, wait: :polynomially_longer, attempts: 5
  
  # Job batching for improved throughput
  def self.batch_process(items, batch_size: 100)
    items.each_slice(batch_size) do |batch|
      BatchProcessJob.perform_later(batch.map(&:id))
    end
  end
  
  def perform(item_ids)
    # Process items efficiently with connection management
    ActiveRecord::Base.connection_pool.with_connection do
      items = Item.where(id: item_ids).includes(:dependencies)
      
      # Use transaction for batch consistency
      ActiveRecord::Base.transaction do
        results = items.map { |item| process_item(item) }
        
        # Bulk operations for better database performance
        ProcessingResult.insert_all(results) if results.any?
      end
    end
  rescue StandardError => e
    # Record job failure metrics
    JobMetrics.increment('job.failure', tags: { 
      job_class: self.class.name,
      error_class: e.class.name
    })
    
    raise
  end
  
  private
  
  def process_item(item)
    start_time = Time.current
    
    # Actual processing logic
    result = perform_complex_calculation(item)
    
    # Record processing metrics
    JobMetrics.timing('item.processing_time', Time.current - start_time)
    
    {
      item_id: item.id,
      result: result,
      processed_at: Time.current,
      processing_duration: Time.current - start_time
    }
  end
end

Reference

Core Integration Classes

Class Purpose Key Methods
Rails::Application Main application configuration and bootstrapping #config, #initialize!, #routes
Rails::Engine Modular application components and gems #isolate_namespace, #config, #initializer
ActionDispatch::MiddlewareStack HTTP request processing pipeline #use, #insert_before, #insert_after, #delete
Rails::Autoloaders Code loading and reloading management #main, #once, #logger=
ActiveSupport::Configurable Configuration management system #configure, #config_accessor

Configuration Options

Configuration Type Description Default
config.load_defaults Float Rails version for default settings Current version
config.autoload_paths Array Directories for automatic code loading ['app/**']
config.eager_load_paths Array Directories loaded at boot time ['app']
config.middleware MiddlewareStack HTTP middleware configuration Default stack
config.cache_store Symbol/Array Caching backend configuration :file_store
config.active_job.queue_adapter Symbol Background job processing system :async
config.log_level Symbol Logging verbosity level :debug
config.time_zone String Application time zone 'UTC'

Middleware Integration Methods

Method Parameters Returns Description
#use(middleware, *args) middleware (Class), args (Array) self Add middleware to end of stack
#insert_before(target, middleware, *args) target (Class), middleware (Class), args (Array) self Insert middleware before target
#insert_after(target, middleware, *args) target (Class), middleware (Class), args (Array) self Insert middleware after target
#delete(middleware) middleware (Class) Class Remove middleware from stack
#swap(target, replacement, *args) target (Class), replacement (Class), args (Array) self Replace middleware in stack

Rails Engine Configuration

Method Parameters Description
isolate_namespace(module) module (Module) Isolate engine namespace from host application
config.generators Block Configure code generators for engine
initializer(name, opts = {}) name (String), opts (Hash) Define initialization hook
config.paths Hash Configure load paths for engine components
config.autoload_once_paths Array Paths loaded once during initialization

Error Classes

Exception Inheritance Description
Rails::Engine::NoSuchRouteError StandardError Engine route not found
Rails::Application::InvalidConfigurationError StandardError Invalid application configuration
ActiveSupport::Dependencies::LoadingError StandardError Autoloading failure
ActionDispatch::MiddlewareStack::MiddlewareNotFound StandardError Middleware not found in stack
Rails::Autoloaders::NameError NameError Autoloading constant resolution failure

Cache Store Options

Store Type Configuration Use Case
:memory_store config.cache_store = :memory_store, { size: 64.megabytes } Single-process development
:file_store config.cache_store = :file_store, '/path/to/cache' Simple file-based caching
:redis_cache_store config.cache_store = :redis_cache_store, { url: 'redis://localhost' } Distributed caching
:mem_cache_store config.cache_store = :mem_cache_store, 'localhost' High-performance caching
:null_store config.cache_store = :null_store Disable caching

ActiveJob Adapters

Adapter Configuration Requirements
:async config.active_job.queue_adapter = :async Built-in, memory-based
:sidekiq config.active_job.queue_adapter = :sidekiq gem 'sidekiq', Redis
:resque config.active_job.queue_adapter = :resque gem 'resque', Redis
:delayed_job config.active_job.queue_adapter = :delayed_job gem 'delayed_job', Database
:sucker_punch config.active_job.queue_adapter = :sucker_punch gem 'sucker_punch'

Environment Configuration Files

File Purpose Loading Order
config/application.rb Base application configuration 1
config/environments/development.rb Development-specific settings 2
config/environments/test.rb Test-specific settings 2
config/environments/production.rb Production-specific settings 2
config/initializers/*.rb Component initialization 3
config/routes.rb URL routing configuration 4

Performance Monitoring Integration

Metric Type Collection Method Example Usage
Request Duration ActiveSupport::Notifications.subscribe Monitor controller action performance
Database Queries ActiveRecord::LogSubscriber Track query count and duration
Cache Operations ActiveSupport::Cache::Store callbacks Monitor cache hit/miss rates
Background Jobs ActiveJob::Callbacks Track job processing metrics
Memory Usage GC.stat, Process monitoring Monitor memory consumption patterns