Framework Overview

Hanami's Componentized Architecture

Hanami enforces a separation of concerns by encouraging apps to be split into isolated components. While this promotes maintainability, it introduces nuances in dependency sharing, state management, and data access across slices.

Why It's a Double-Edged Sword

  • Service isolation can hide shared state issues
  • Non-global routes or helpers can confuse newcomers
  • Shared libraries between slices may introduce circular dependencies

Common Production Troubles

1. Inconsistent Dependency Injection (DI)

Hanami's container-based DI (via dry-system) can become inconsistent during boot if components are lazily loaded or misconfigured in boot/ and lib/.

# boot/system.rb
Dry::System.register(:mailer, MyMailer)
# But later...
# undefined method error when injected

Fix: Always declare boot-time components explicitly and verify order of system boot stages.

2. Memory Leaks in Long-Lived Services

Hanami apps embedded in job runners or websockets (e.g., Sidekiq + Hanami app container) can suffer memory bloat due to thread-local state.

# Anti-pattern
Thread.current[:context] = my_object
# Never cleared leads to growth over time

Solution: Use request-scoped or explicitly scoped memory containers.

3. Broken Asset Pipeline in Production

Hanami uses its own asset compiler. In misconfigured Docker builds or CI/CD, assets may silently fail to compile.

# production.rb
assets.digest = true
assets.compile = false

Debug tip: Add verbose output and CI validation for asset compilation.

Diagnosing Hanami Issues

1. Boot-Time Failures

Use HANAMI_ENV=production hanami boot to test in production mode locally. This surfaces missing components or misordered initializations.

2. Misbehaving Actions or Routes

Use hanami routes to confirm route recognition. Mismatches often stem from slice isolation or router conflicts in multi-app setups.

3. Event Bus Failures

Hanami's event system may silently fail if subscribers aren't registered during boot.

# boot/events.rb
register "user.created", MyListener.new

Check: Validate that boot/events.rb is eagerly loaded.

Advanced Fixes

1. Custom Middleware Debugging

# config.ru
use MyTracingMiddleware
run Hanami.app

Ensure middleware respects Hanami's rack stack, especially when injecting observability or auth layers.

2. Auto-Registration Troubles

Dry-system auto-registration can miss files if naming doesn't follow conventions.

# Wrong
users_service.rb
# Correct
users_service.rb with UsersService class

Use Hanami.boot.container.keys to list all registered components for verification.

Best Practices

  • Always run hanami generate action to respect naming/layout conventions
  • Monitor memory with tools like derailed_benchmarks or heap-profiler
  • Enforce asset compilation in CI pipelines before container image creation
  • Use clear boundaries between slices—avoid leaking service logic across domains
  • Enable verbose boot logs during deployment dry runs

Conclusion

While Hanami brings elegance and order to Ruby back-end development, its architectural rigor introduces its own class of hidden challenges. Effective troubleshooting requires a deep understanding of component boot flows, dry-system conventions, and memory patterns. By mastering the framework's internals and investing in systematic diagnostics, teams can scale Hanami confidently in complex enterprise environments.

FAQs

1. Why do some of my services fail to auto-load in production?

Likely due to naming mismatches or misconfigured auto_register: false flags in dry-system. Confirm the class and filename match exactly.

2. How can I track down memory leaks in a Hanami app?

Use heap-profiler or derailed_benchmarks and look for retained objects in long-lived threads or jobs.

3. Is it safe to use global state inside Hanami slices?

No. Slices should remain isolated. Shared global state introduces tight coupling and brittle boundaries.

4. Why aren't my event subscribers firing?

They may not be registered during the boot process. Ensure the relevant boot file is loaded and events are subscribed before app initialization completes.

5. Can I mix Hanami and Rails engines in one system?

Technically possible via Rack composition, but strongly discouraged due to conflicting conventions, DI systems, and lifecycle management.