Puma plugin in my Rails app

Hi there!

I’m trying to write my first Puma plugin, copying tmp_restart.rb as example and place the code inside libdirectory of my Rails app.

lib/puma/plugin/pruebas.rb:

# frozen_string_literal: true

require 'puma/plugin'

Puma::Plugin.create do
  def start(launcher)
    puts 'Hola mundo!'

    p ['launcher', launcher]

    in_background do
      loop do
        sleep 2

        puts 'Hello world!'
      end
    end
  end
end

And I add these lines to puma.rb:

# Plugin Pruebas
plugin :pruebas

But when I run bin/rails server I got this error:

=> Booting Puma
=> Rails 7.1.3.2 application starting in development 
=> Run `bin/rails server --help` for more startup options
Exiting
/usr/local/lib/ruby/gems/3.3.0/gems/puma-6.4.2/lib/puma/plugin.rb:76:in `<module:Puma>': Plugin is not a class (TypeError)
/usr/local/lib/ruby/gems/3.3.0/gems/zeitwerk-2.6.13/lib/zeitwerk/loader/callbacks.rb:56: previous definition of Plugin was here
	from /usr/local/lib/ruby/gems/3.3.0/gems/puma-6.4.2/lib/puma/plugin.rb:3:in `<main>'
	from /usr/local/lib/ruby/gems/3.3.0/gems/puma-6.4.2/lib/puma/configuration.rb:4:in `require_relative'
	from /usr/local/lib/ruby/gems/3.3.0/gems/puma-6.4.2/lib/puma/configuration.rb:4:in `<main>'
	from /usr/local/lib/ruby/gems/3.3.0/gems/puma-6.4.2/lib/rack/handler/puma.rb:13:in `require_relative'
	from /usr/local/lib/ruby/gems/3.3.0/gems/puma-6.4.2/lib/rack/handler/puma.rb:13:in `config'
	from /usr/local/lib/ruby/gems/3.3.0/gems/puma-6.4.2/lib/rack/handler/puma.rb:68:in `run'
	from /usr/local/lib/ruby/gems/3.3.0/gems/rackup-2.1.0/lib/rackup/server.rb:341:in `start'
	from /usr/local/lib/ruby/gems/3.3.0/gems/railties-7.1.3.2/lib/rails/commands/server/server_command.rb:38:in `start'
	from /usr/local/lib/ruby/gems/3.3.0/gems/railties-7.1.3.2/lib/rails/commands/server/server_command.rb:145:in `block in perform'
	from <internal:kernel>:90:in `tap'
	from /usr/local/lib/ruby/gems/3.3.0/gems/railties-7.1.3.2/lib/rails/commands/server/server_command.rb:136:in `perform'
	from /usr/local/lib/ruby/gems/3.3.0/gems/thor-1.3.1/lib/thor/command.rb:28:in `run'
	from /usr/local/lib/ruby/gems/3.3.0/gems/thor-1.3.1/lib/thor/invocation.rb:127:in `invoke_command'
	from /usr/local/lib/ruby/gems/3.3.0/gems/railties-7.1.3.2/lib/rails/command/base.rb:178:in `invoke_command'
	from /usr/local/lib/ruby/gems/3.3.0/gems/thor-1.3.1/lib/thor.rb:527:in `dispatch'
	from /usr/local/lib/ruby/gems/3.3.0/gems/railties-7.1.3.2/lib/rails/command/base.rb:73:in `perform'
	from /usr/local/lib/ruby/gems/3.3.0/gems/railties-7.1.3.2/lib/rails/command.rb:71:in `block in invoke'
	from /usr/local/lib/ruby/gems/3.3.0/gems/railties-7.1.3.2/lib/rails/command.rb:149:in `with_argv'
	from /usr/local/lib/ruby/gems/3.3.0/gems/railties-7.1.3.2/lib/rails/command.rb:69:in `invoke'
	from /usr/local/lib/ruby/gems/3.3.0/gems/railties-7.1.3.2/lib/rails/commands.rb:18:in `<main>'
	from /usr/local/lib/ruby/3.3.0/bundled_gems.rb:74:in `require'
	from /usr/local/lib/ruby/3.3.0/bundled_gems.rb:74:in `block (2 levels) in replace_require'
	from /usr/local/lib/ruby/gems/3.3.0/gems/bootsnap-1.18.3/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
	from bin/rails:4:in `<main>'

As you can see I run: ruby: 3.3.0 rails: 7.1.3.2 puma: 6.4.2

Since it has not been told otherwise, the autoloader manages lib/puma and believes lib/puma/plugin represents a module, creates one on the fly, and when later Puma tries to define Puma::Plugin, the type does not match.

But that is just the side-effect, the root thing to address here is that the autoloader should not manage lib/puma, the files there are loaded by hand by Puma. You put them in lib for convenience only.

Just tell the autoloader to ignore that subdirectory:

# config/application.rb

config.autoload_lib(ignore: %w(assets ... puma))