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
orheap-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.