Class: PumaPlus::Launcher

Inherits:
Object
  • Object
show all
Defined in:
lib/puma_plus/launcher.rb

Overview

The puma-plus command.

Ruby parses the configuration and then execs the Go server. Two decisions worth stating, because both could reasonably have gone the other way.

Why Ruby reads the config: it is a Ruby file. Worker counts get computed from Etc.nprocessors, settings branch on the environment, and lifecycle hooks are blocks. Only Ruby can evaluate that, and a config format Go could parse would be a worse config format.

Why exec rather than spawn: exec replaces this process, so the Go server ends up with the pid the shell started, inherits the terminal and the process group directly, and receives signals from the user with nothing in between. A supervising Ruby parent would have to forward signals, mirror exit statuses, and would show up as a stray process in every ps -- all to supervise a process that supervises Ruby itself. After exec there is no Ruby in the tree except the workers the Go server starts.

Constant Summary collapse

DEFAULTS =
{
  listen: "0.0.0.0:9292",
  control: "127.0.0.1:9293",
  app: "config.ru",
  threads: 5,
  workers: 1,
  environment: "development"
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(argv, stdout: $stdout, stderr: $stderr, env: ENV) ⇒ Launcher

Returns a new instance of Launcher.



40
41
42
43
44
45
46
# File 'lib/puma_plus/launcher.rb', line 40

def initialize(argv, stdout: $stdout, stderr: $stderr, env: ENV)
  @argv = argv
  @stdout = stdout
  @stderr = stderr
  @env = env
  @options = Options.new(DEFAULTS.dup)
end

Instance Attribute Details

#optionsObject (readonly)

Returns the value of attribute options.



48
49
50
# File 'lib/puma_plus/launcher.rb', line 48

def options
  @options
end

Class Method Details

.config_candidates(env) ⇒ Object

Searched in order, mirroring puma's config/puma/.rb then config/puma.rb.



36
37
38
# File 'lib/puma_plus/launcher.rb', line 36

def self.config_candidates(env)
  ["config/puma-plus/#{env}.rb", "config/puma-plus.rb"]
end

Instance Method Details

#runObject



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/puma_plus/launcher.rb', line 50

def run
  parse_cli!

  # RACK_ENV is consulted before the config file is chosen, because which
  # file gets loaded depends on the environment.
  if (e = @env["RACK_ENV"]) && !@options.user.key?(:environment)
    @options.default[:environment] = e
  end

  dsl = load_config!
  Dir.chdir(@options[:directory]) if @options[:directory]

  (dsl&.warnings || []).each { |w| @stderr.puts "[puma-plus] config: #{w}" }
  validate!

  argv = go_argv
  if @dry_run
    print_plan(argv)
    return 0
  end

  write_pidfile
  exec_go(argv)
rescue ConfigError, URI::Error, OptionParser::ParseError, ArgumentError => e
  @stderr.puts "[puma-plus] #{e.message}"
  1
end