Skip to content

Instantly share code, notes, and snippets.

@jodosha
Created October 6, 2023 08:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jodosha/9d18fa71ffaddee6754ac377eb2e325a to your computer and use it in GitHub Desktop.
Save jodosha/9d18fa71ffaddee6754ac377eb2e325a to your computer and use it in GitHub Desktop.
Hanami DEV Memory Footprint

Assessment

This is a memory footprint assessment of all the possibilities to start the Rack server and the assets watch. I know this isn't a scientific approach, but it gives us the order of magnitude of the differences between the options.

Conclusions

  • Using Ruby and NPM as middlemen to execute other commands wastes memory.
    • bundle exec hanami server and assets, npm exec
  • Foreman executes 3 Ruby processes.
  • Guard executes 2 Ruby and 1 UNIX processes.
  • The official way (as of v2.1.0.beta2) is hanami dev consumes the most memory: 227 Mb
  • There are less memory hungry solutions (57 Mb) that require other considerations: installing extra tools

Data

Config

Puma

# frozen_string_literal: true

max_threads_count = ENV.fetch("HANAMI_MAX_THREADS", 5)
min_threads_count = ENV.fetch("HANAMI_MIN_THREADS") { max_threads_count }
threads min_threads_count, max_threads_count

port        ENV.fetch("HANAMI_PORT", 2300)
environment ENV.fetch("HANAMI_ENV", "development")
workers     ENV.fetch("HANAMI_WEB_CONCURRENCY", 0)

if ENV.fetch("HANAMI_WEB_CONCURRENCY", 0) > 0
  on_worker_shutdown do
    Hanami.shutdown
  end
end

preload_app!

Procfile

web: bundle exec hanami server
assets: bundle exec hanami assets watch

Guardfile

# frozen_string_literal: true

group :server do
  guard "puma", port: ENV.fetch("HANAMI_PORT", 2300) do
    watch(%r{config/*})
    watch(%r{lib/*})
    watch(%r{app/[^/]+.rb})
    watch(%r{app/templates/.+..+..+})
    watch(%r{slices/.+/.+.rb})
    watch(%r{slices/.+/templates/.+..+..+})
  end
end

HTTP

Rackup [36.6Mb]

  • Server: 36.6 Mb
$ bundle exec rackup

Puma [37.3 Mb]

  • Server: 37.3 Mb
$ bundle exec puma

Hanami Server (no code reloading) [39.7 Mb]

  • Server: 39.7 Mb
$ bundle exec hanami server --no-code-reloading

Hanami Server (w/ code reloading, using Guard) [85.5 Mb]

  • Server: 34.4 Mb
  • Guard (main): 32 Mb
  • Guard (child): 19.1 Mb

Assets

Node Assets watch [17.5 Mb]

  • Node: 17.5 Mb
$ node_modules/hanami-assets/dist/hanami-assets.js --watch

NPM Assets watch [50.1 Mb]

  • NPM: 31.9 Mb
  • Node: 18.2 Mb
$ npm exec hanami-assets -- --watch

Dev

Foreman [185.6 Mb]

  • Foreman: 15.6 Mb
  • Foreman (web, Guard main): 19 Mb
  • Guard (Puma): 32.8 Mb
  • Foreman (assets): 36 Mb
  • Puma: 34 Mb
  • fsevent_watch: 1.1 Mb
  • Node: 17.1 Mb
  • NPM: 30 Mb

Hanami Dev (code reloading + assets watch) [227.3 Mb]

  • Hanami Dev: 34.4 Mb
  • Hanami Assets Watch: 35.7 Mb
  • Foreman: 16.1 Mb
  • Foreman (web, Guard main): 19.5 Mb
  • Foreman (assets): 35.7 Mb
  • Puma: 35.0 Mb
  • NPM: 31.7 Mb
  • NPM: 18.1 Mb
  • fsevent_watch: 1.1 Mb

bin/dev (shoreman + watchexec) [57.2 Mb]

Shoreman is a Foreman replacement. https://github.com/chrismytton/shoreman Watchexec is a Guard replacement. https://github.com/watchexec/watchexec

  • Puma: 36.5 Mb
  • Node: 18.0 Mb
  • watchexec: 2.7 Mb

bin/dev

#!/usr/bin/env sh
shoreman Procfile.dev

Procfile.dev

web: watchexec -w app -w config -w lib -w slices --exts rb,erb,haml,slim -r "bundle exec rackup -p 2300"
assets: node_modules/hanami-assets/dist/hanami-assets.js --watch

Notes for this option:

  • PRO: We save 170 Mb if compared with the current implementation of hanami dev
  • PRO: We can remove hanami-reloader, guard, and guard-puma as development deps.
  • CONS: We need to distribute shoreman. It isn't hard, it's a Bash script, we can vendor in Hanami.
  • CONS: We need users to install watchexec. It's distributed via all the common package managers.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment