PageRenderTime 51ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/unicorn/configurator.rb

https://github.com/plasticcube/unicorn
Ruby | 654 lines | 257 code | 49 blank | 348 comment | 27 complexity | c3e7a34886d47971b14a3a128232f207 MD5 | raw file
Possible License(s): GPL-3.0
  1. # -*- encoding: binary -*-
  2. require 'logger'
  3. require 'unicorn/ssl_configurator'
  4. # Implements a simple DSL for configuring a \Unicorn server.
  5. #
  6. # See http://unicorn.bogomips.org/examples/unicorn.conf.rb and
  7. # http://unicorn.bogomips.org/examples/unicorn.conf.minimal.rb
  8. # example configuration files. An example config file for use with
  9. # nginx is also available at
  10. # http://unicorn.bogomips.org/examples/nginx.conf
  11. #
  12. # See the link:/TUNING.html document for more information on tuning unicorn.
  13. class Unicorn::Configurator
  14. include Unicorn
  15. include Unicorn::SSLConfigurator
  16. # :stopdoc:
  17. attr_accessor :set, :config_file, :after_reload
  18. # used to stash stuff for deferred processing of cli options in
  19. # config.ru after "working_directory" is bound. Do not rely on
  20. # this being around later on...
  21. RACKUP = {
  22. :daemonize => false,
  23. :host => Unicorn::Const::DEFAULT_HOST,
  24. :port => Unicorn::Const::DEFAULT_PORT,
  25. :set_listener => false,
  26. :options => { :listeners => [] }
  27. }
  28. # Default settings for Unicorn
  29. DEFAULTS = {
  30. :timeout => 60,
  31. :logger => Logger.new($stderr),
  32. :worker_processes => 1,
  33. :after_fork => lambda { |server, worker|
  34. server.logger.info("worker=#{worker.nr} spawned pid=#{$$}")
  35. },
  36. :before_fork => lambda { |server, worker|
  37. server.logger.info("worker=#{worker.nr} spawning...")
  38. },
  39. :before_exec => lambda { |server|
  40. server.logger.info("forked child re-executing...")
  41. },
  42. :pid => nil,
  43. :preload_app => false,
  44. :check_client_connection => false,
  45. :rewindable_input => true, # for Rack 2.x: (Rack::VERSION[0] <= 1),
  46. :client_body_buffer_size => Unicorn::Const::MAX_BODY,
  47. :trust_x_forwarded => true,
  48. }
  49. #:startdoc:
  50. def initialize(defaults = {}) #:nodoc:
  51. self.set = Hash.new(:unset)
  52. @use_defaults = defaults.delete(:use_defaults)
  53. self.config_file = defaults.delete(:config_file)
  54. # after_reload is only used by unicorn_rails, unsupported otherwise
  55. self.after_reload = defaults.delete(:after_reload)
  56. set.merge!(DEFAULTS) if @use_defaults
  57. defaults.each { |key, value| self.__send__(key, value) }
  58. Hash === set[:listener_opts] or
  59. set[:listener_opts] = Hash.new { |hash,key| hash[key] = {} }
  60. Array === set[:listeners] or set[:listeners] = []
  61. reload(false)
  62. end
  63. def reload(merge_defaults = true) #:nodoc:
  64. if merge_defaults && @use_defaults
  65. set.merge!(DEFAULTS) if @use_defaults
  66. end
  67. instance_eval(File.read(config_file), config_file) if config_file
  68. parse_rackup_file
  69. RACKUP[:set_listener] and
  70. set[:listeners] << "#{RACKUP[:host]}:#{RACKUP[:port]}"
  71. # unicorn_rails creates dirs here after working_directory is bound
  72. after_reload.call if after_reload
  73. # working_directory binds immediately (easier error checking that way),
  74. # now ensure any paths we changed are correctly set.
  75. [ :pid, :stderr_path, :stdout_path ].each do |var|
  76. String === (path = set[var]) or next
  77. path = File.expand_path(path)
  78. File.writable?(path) || File.writable?(File.dirname(path)) or \
  79. raise ArgumentError, "directory for #{var}=#{path} not writable"
  80. end
  81. end
  82. def commit!(server, options = {}) #:nodoc:
  83. skip = options[:skip] || []
  84. if ready_pipe = RACKUP.delete(:ready_pipe)
  85. server.ready_pipe = ready_pipe
  86. end
  87. if set[:check_client_connection]
  88. set[:listeners].each do |address|
  89. if set[:listener_opts][address][:tcp_nopush] == true
  90. raise ArgumentError,
  91. "check_client_connection is incompatible with tcp_nopush:true"
  92. end
  93. end
  94. end
  95. set.each do |key, value|
  96. value == :unset and next
  97. skip.include?(key) and next
  98. server.__send__("#{key}=", value)
  99. end
  100. end
  101. def [](key) # :nodoc:
  102. set[key]
  103. end
  104. # sets object to the +obj+ Logger-like object. The new Logger-like
  105. # object must respond to the following methods:
  106. # * debug
  107. # * info
  108. # * warn
  109. # * error
  110. # * fatal
  111. # The default Logger will log its output to the path specified
  112. # by +stderr_path+. If you're running Unicorn daemonized, then
  113. # you must specify a path to prevent error messages from going
  114. # to /dev/null.
  115. def logger(obj)
  116. %w(debug info warn error fatal).each do |m|
  117. obj.respond_to?(m) and next
  118. raise ArgumentError, "logger=#{obj} does not respond to method=#{m}"
  119. end
  120. set[:logger] = obj
  121. end
  122. # sets after_fork hook to a given block. This block will be called by
  123. # the worker after forking. The following is an example hook which adds
  124. # a per-process listener to every worker:
  125. #
  126. # after_fork do |server,worker|
  127. # # per-process listener ports for debugging/admin:
  128. # addr = "127.0.0.1:#{9293 + worker.nr}"
  129. #
  130. # # the negative :tries parameter indicates we will retry forever
  131. # # waiting on the existing process to exit with a 5 second :delay
  132. # # Existing options for Unicorn::Configurator#listen such as
  133. # # :backlog, :rcvbuf, :sndbuf are available here as well.
  134. # server.listen(addr, :tries => -1, :delay => 5, :backlog => 128)
  135. # end
  136. def after_fork(*args, &block)
  137. set_hook(:after_fork, block_given? ? block : args[0])
  138. end
  139. # sets before_fork got be a given Proc object. This Proc
  140. # object will be called by the master process before forking
  141. # each worker.
  142. def before_fork(*args, &block)
  143. set_hook(:before_fork, block_given? ? block : args[0])
  144. end
  145. # sets the before_exec hook to a given Proc object. This
  146. # Proc object will be called by the master process right
  147. # before exec()-ing the new unicorn binary. This is useful
  148. # for freeing certain OS resources that you do NOT wish to
  149. # share with the reexeced child process.
  150. # There is no corresponding after_exec hook (for obvious reasons).
  151. def before_exec(*args, &block)
  152. set_hook(:before_exec, block_given? ? block : args[0], 1)
  153. end
  154. # sets the timeout of worker processes to +seconds+. Workers
  155. # handling the request/app.call/response cycle taking longer than
  156. # this time period will be forcibly killed (via SIGKILL). This
  157. # timeout is enforced by the master process itself and not subject
  158. # to the scheduling limitations by the worker process. Due the
  159. # low-complexity, low-overhead implementation, timeouts of less
  160. # than 3.0 seconds can be considered inaccurate and unsafe.
  161. #
  162. # For running Unicorn behind nginx, it is recommended to set
  163. # "fail_timeout=0" for in your nginx configuration like this
  164. # to have nginx always retry backends that may have had workers
  165. # SIGKILL-ed due to timeouts.
  166. #
  167. # # See http://wiki.nginx.org/NginxHttpUpstreamModule for more details
  168. # # on nginx upstream configuration:
  169. # upstream unicorn_backend {
  170. # # for UNIX domain socket setups:
  171. # server unix:/path/to/unicorn.sock fail_timeout=0;
  172. #
  173. # # for TCP setups
  174. # server 192.168.0.7:8080 fail_timeout=0;
  175. # server 192.168.0.8:8080 fail_timeout=0;
  176. # server 192.168.0.9:8080 fail_timeout=0;
  177. # }
  178. def timeout(seconds)
  179. set_int(:timeout, seconds, 3)
  180. # POSIX says 31 days is the smallest allowed maximum timeout for select()
  181. max = 30 * 60 * 60 * 24
  182. set[:timeout] = seconds > max ? max : seconds
  183. end
  184. # sets the current number of worker_processes to +nr+. Each worker
  185. # process will serve exactly one client at a time. You can
  186. # increment or decrement this value at runtime by sending SIGTTIN
  187. # or SIGTTOU respectively to the master process without reloading
  188. # the rest of your Unicorn configuration. See the SIGNALS document
  189. # for more information.
  190. def worker_processes(nr)
  191. set_int(:worker_processes, nr, 1)
  192. end
  193. # sets listeners to the given +addresses+, replacing or augmenting the
  194. # current set. This is for the global listener pool shared by all
  195. # worker processes. For per-worker listeners, see the after_fork example
  196. # This is for internal API use only, do not use it in your Unicorn
  197. # config file. Use listen instead.
  198. def listeners(addresses) # :nodoc:
  199. Array === addresses or addresses = Array(addresses)
  200. addresses.map! { |addr| expand_addr(addr) }
  201. set[:listeners] = addresses
  202. end
  203. # Adds an +address+ to the existing listener set. May be specified more
  204. # than once. +address+ may be an Integer port number for a TCP port, an
  205. # "IP_ADDRESS:PORT" for TCP listeners or a pathname for UNIX domain sockets.
  206. #
  207. # listen 3000 # listen to port 3000 on all TCP interfaces
  208. # listen "127.0.0.1:3000" # listen to port 3000 on the loopback interface
  209. # listen "/tmp/.unicorn.sock" # listen on the given Unix domain socket
  210. # listen "[::1]:3000" # listen to port 3000 on the IPv6 loopback interface
  211. #
  212. # The following options may be specified (but are generally not needed):
  213. #
  214. # [:backlog => number of clients]
  215. #
  216. # This is the backlog of the listen() syscall.
  217. #
  218. # Some operating systems allow negative values here to specify the
  219. # maximum allowable value. In most cases, this number is only
  220. # recommendation and there are other OS-specific tunables and
  221. # variables that can affect this number. See the listen(2)
  222. # syscall documentation of your OS for the exact semantics of
  223. # this.
  224. #
  225. # If you are running unicorn on multiple machines, lowering this number
  226. # can help your load balancer detect when a machine is overloaded
  227. # and give requests to a different machine.
  228. #
  229. # Default: 1024
  230. #
  231. # [:rcvbuf => bytes, :sndbuf => bytes]
  232. #
  233. # Maximum receive and send buffer sizes (in bytes) of sockets.
  234. #
  235. # These correspond to the SO_RCVBUF and SO_SNDBUF settings which
  236. # can be set via the setsockopt(2) syscall. Some kernels
  237. # (e.g. Linux 2.4+) have intelligent auto-tuning mechanisms and
  238. # there is no need (and it is sometimes detrimental) to specify them.
  239. #
  240. # See the socket API documentation of your operating system
  241. # to determine the exact semantics of these settings and
  242. # other operating system-specific knobs where they can be
  243. # specified.
  244. #
  245. # Defaults: operating system defaults
  246. #
  247. # [:tcp_nodelay => true or false]
  248. #
  249. # Disables Nagle's algorithm on TCP sockets if +true+.
  250. #
  251. # Setting this to +true+ can make streaming responses in Rails 3.1
  252. # appear more quickly at the cost of slightly higher bandwidth usage.
  253. # The effect of this option is most visible if nginx is not used,
  254. # but nginx remains highly recommended with \Unicorn.
  255. #
  256. # This has no effect on UNIX sockets.
  257. #
  258. # Default: +true+ (Nagle's algorithm disabled) in \Unicorn,
  259. # +true+ in Rainbows! This defaulted to +false+ in \Unicorn
  260. # 3.x
  261. #
  262. # [:tcp_nopush => true or false]
  263. #
  264. # Enables/disables TCP_CORK in Linux or TCP_NOPUSH in FreeBSD
  265. #
  266. # This prevents partial TCP frames from being sent out and reduces
  267. # wakeups in nginx if it is on a different machine. Since \Unicorn
  268. # is only designed for applications that send the response body
  269. # quickly without keepalive, sockets will always be flushed on close
  270. # to prevent delays.
  271. #
  272. # This has no effect on UNIX sockets.
  273. #
  274. # Default: +false+
  275. # This defaulted to +true+ in \Unicorn 3.4 - 3.7
  276. #
  277. # [:ipv6only => true or false]
  278. #
  279. # This option makes IPv6-capable TCP listeners IPv6-only and unable
  280. # to receive IPv4 queries on dual-stack systems. A separate IPv4-only
  281. # listener is required if this is true.
  282. #
  283. # This option is only available for Ruby 1.9.2 and later.
  284. #
  285. # Enabling this option for the IPv6-only listener and having a
  286. # separate IPv4 listener is recommended if you wish to support IPv6
  287. # on the same TCP port. Otherwise, the value of \env[\"REMOTE_ADDR\"]
  288. # will appear as an ugly IPv4-mapped-IPv6 address for IPv4 clients
  289. # (e.g ":ffff:10.0.0.1" instead of just "10.0.0.1").
  290. #
  291. # Default: Operating-system dependent
  292. #
  293. # [:tries => Integer]
  294. #
  295. # Times to retry binding a socket if it is already in use
  296. #
  297. # A negative number indicates we will retry indefinitely, this is
  298. # useful for migrations and upgrades when individual workers
  299. # are binding to different ports.
  300. #
  301. # Default: 5
  302. #
  303. # [:delay => seconds]
  304. #
  305. # Seconds to wait between successive +tries+
  306. #
  307. # Default: 0.5 seconds
  308. #
  309. # [:umask => mode]
  310. #
  311. # Sets the file mode creation mask for UNIX sockets. If specified,
  312. # this is usually in octal notation.
  313. #
  314. # Typically UNIX domain sockets are created with more liberal
  315. # file permissions than the rest of the application. By default,
  316. # we create UNIX domain sockets to be readable and writable by
  317. # all local users to give them the same accessibility as
  318. # locally-bound TCP listeners.
  319. #
  320. # This has no effect on TCP listeners.
  321. #
  322. # Default: 0000 (world-read/writable)
  323. #
  324. # [:tcp_defer_accept => Integer]
  325. #
  326. # Defer accept() until data is ready (Linux-only)
  327. #
  328. # For Linux 2.6.32 and later, this is the number of retransmits to
  329. # defer an accept() for if no data arrives, but the client will
  330. # eventually be accepted after the specified number of retransmits
  331. # regardless of whether data is ready.
  332. #
  333. # For Linux before 2.6.32, this is a boolean option, and
  334. # accepts are _always_ deferred indefinitely if no data arrives.
  335. # This is similar to <code>:accept_filter => "dataready"</code>
  336. # under FreeBSD.
  337. #
  338. # Specifying +true+ is synonymous for the default value(s) below,
  339. # and +false+ or +nil+ is synonymous for a value of zero.
  340. #
  341. # A value of +1+ is a good optimization for local networks
  342. # and trusted clients. For Rainbows! and Zbatery users, a higher
  343. # value (e.g. +60+) provides more protection against some
  344. # denial-of-service attacks. There is no good reason to ever
  345. # disable this with a +zero+ value when serving HTTP.
  346. #
  347. # Default: 1 retransmit for \Unicorn, 60 for Rainbows! 0.95.0\+
  348. #
  349. # [:accept_filter => String]
  350. #
  351. # defer accept() until data is ready (FreeBSD-only)
  352. #
  353. # This enables either the "dataready" or (default) "httpready"
  354. # accept() filter under FreeBSD. This is intended as an
  355. # optimization to reduce context switches with common GET/HEAD
  356. # requests. For Rainbows! and Zbatery users, this provides
  357. # some protection against certain denial-of-service attacks, too.
  358. #
  359. # There is no good reason to change from the default.
  360. #
  361. # Default: "httpready"
  362. def listen(address, options = {})
  363. address = expand_addr(address)
  364. if String === address
  365. [ :umask, :backlog, :sndbuf, :rcvbuf, :tries ].each do |key|
  366. value = options[key] or next
  367. Integer === value or
  368. raise ArgumentError, "not an integer: #{key}=#{value.inspect}"
  369. end
  370. [ :tcp_nodelay, :tcp_nopush, :ipv6only ].each do |key|
  371. (value = options[key]).nil? and next
  372. TrueClass === value || FalseClass === value or
  373. raise ArgumentError, "not boolean: #{key}=#{value.inspect}"
  374. end
  375. unless (value = options[:delay]).nil?
  376. Numeric === value or
  377. raise ArgumentError, "not numeric: delay=#{value.inspect}"
  378. end
  379. set[:listener_opts][address].merge!(options)
  380. end
  381. set[:listeners] << address
  382. end
  383. # sets the +path+ for the PID file of the unicorn master process
  384. def pid(path); set_path(:pid, path); end
  385. # Enabling this preloads an application before forking worker
  386. # processes. This allows memory savings when using a
  387. # copy-on-write-friendly GC but can cause bad things to happen when
  388. # resources like sockets are opened at load time by the master
  389. # process and shared by multiple children. People enabling this are
  390. # highly encouraged to look at the before_fork/after_fork hooks to
  391. # properly close/reopen sockets. Files opened for logging do not
  392. # have to be reopened as (unbuffered-in-userspace) files opened with
  393. # the File::APPEND flag are written to atomically on UNIX.
  394. #
  395. # In addition to reloading the unicorn-specific config settings,
  396. # SIGHUP will reload application code in the working
  397. # directory/symlink when workers are gracefully restarted when
  398. # preload_app=false (the default). As reloading the application
  399. # sometimes requires RubyGems updates, +Gem.refresh+ is always
  400. # called before the application is loaded (for RubyGems users).
  401. #
  402. # During deployments, care should _always_ be taken to ensure your
  403. # applications are properly deployed and running. Using
  404. # preload_app=false (the default) means you _must_ check if
  405. # your application is responding properly after a deployment.
  406. # Improperly deployed applications can go into a spawn loop
  407. # if the application fails to load. While your children are
  408. # in a spawn loop, it is is possible to fix an application
  409. # by properly deploying all required code and dependencies.
  410. # Using preload_app=true means any application load error will
  411. # cause the master process to exit with an error.
  412. def preload_app(bool)
  413. set_bool(:preload_app, bool)
  414. end
  415. # Toggles making \env[\"rack.input\"] rewindable.
  416. # Disabling rewindability can improve performance by lowering
  417. # I/O and memory usage for applications that accept uploads.
  418. # Keep in mind that the Rack 1.x spec requires
  419. # \env[\"rack.input\"] to be rewindable, so this allows
  420. # intentionally violating the current Rack 1.x spec.
  421. #
  422. # +rewindable_input+ defaults to +true+ when used with Rack 1.x for
  423. # Rack conformance. When Rack 2.x is finalized, this will most
  424. # likely default to +false+ while still conforming to the newer
  425. # (less demanding) spec.
  426. def rewindable_input(bool)
  427. set_bool(:rewindable_input, bool)
  428. end
  429. # The maximum size (in +bytes+) to buffer in memory before
  430. # resorting to a temporary file. Default is 112 kilobytes.
  431. # This option has no effect if "rewindable_input" is set to
  432. # +false+.
  433. def client_body_buffer_size(bytes)
  434. set_int(:client_body_buffer_size, bytes, 0)
  435. end
  436. # When enabled, unicorn will check the client connection by writing
  437. # the beginning of the HTTP headers before calling the application.
  438. #
  439. # This will prevent calling the application for clients who have
  440. # disconnected while their connection was queued.
  441. #
  442. # This only affects clients connecting over Unix domain sockets
  443. # and TCP via loopback (127.*.*.*). It is unlikely to detect
  444. # disconnects if the client is on a remote host (even on a fast LAN).
  445. #
  446. # This option cannot be used in conjunction with :tcp_nopush.
  447. def check_client_connection(bool)
  448. set_bool(:check_client_connection, bool)
  449. end
  450. # Allow redirecting $stderr to a given path. Unlike doing this from
  451. # the shell, this allows the unicorn process to know the path its
  452. # writing to and rotate the file if it is used for logging. The
  453. # file will be opened with the File::APPEND flag and writes
  454. # synchronized to the kernel (but not necessarily to _disk_) so
  455. # multiple processes can safely append to it.
  456. #
  457. # If you are daemonizing and using the default +logger+, it is important
  458. # to specify this as errors will otherwise be lost to /dev/null.
  459. # Some applications/libraries may also triggering warnings that go to
  460. # stderr, and they will end up here.
  461. def stderr_path(path)
  462. set_path(:stderr_path, path)
  463. end
  464. # Same as stderr_path, except for $stdout. Not many Rack applications
  465. # write to $stdout, but any that do will have their output written here.
  466. # It is safe to point this to the same location a stderr_path.
  467. # Like stderr_path, this defaults to /dev/null when daemonized.
  468. def stdout_path(path)
  469. set_path(:stdout_path, path)
  470. end
  471. # sets the working directory for Unicorn. This ensures SIGUSR2 will
  472. # start a new instance of Unicorn in this directory. This may be
  473. # a symlink, a common scenario for Capistrano users. Unlike
  474. # all other Unicorn configuration directives, this binds immediately
  475. # for error checking and cannot be undone by unsetting it in the
  476. # configuration file and reloading.
  477. def working_directory(path)
  478. # just let chdir raise errors
  479. path = File.expand_path(path)
  480. if config_file &&
  481. config_file[0] != ?/ &&
  482. ! File.readable?("#{path}/#{config_file}")
  483. raise ArgumentError,
  484. "config_file=#{config_file} would not be accessible in" \
  485. " working_directory=#{path}"
  486. end
  487. Dir.chdir(path)
  488. Unicorn::HttpServer::START_CTX[:cwd] = ENV["PWD"] = path
  489. end
  490. # Runs worker processes as the specified +user+ and +group+.
  491. # The master process always stays running as the user who started it.
  492. # This switch will occur after calling the after_fork hook, and only
  493. # if the Worker#user method is not called in the after_fork hook
  494. # +group+ is optional and will not change if unspecified.
  495. def user(user, group = nil)
  496. # raises ArgumentError on invalid user/group
  497. Etc.getpwnam(user)
  498. Etc.getgrnam(group) if group
  499. set[:user] = [ user, group ]
  500. end
  501. # Sets whether or not the parser will trust X-Forwarded-Proto and
  502. # X-Forwarded-SSL headers and set "rack.url_scheme" to "https" accordingly.
  503. # Rainbows!/Zbatery installations facing untrusted clients directly
  504. # should set this to +false+. This is +true+ by default as Unicorn
  505. # is designed to only sit behind trusted nginx proxies.
  506. #
  507. # This has never been publically documented and is subject to removal
  508. # in future releases.
  509. def trust_x_forwarded(bool) # :nodoc:
  510. set_bool(:trust_x_forwarded, bool)
  511. end
  512. # expands "unix:path/to/foo" to a socket relative to the current path
  513. # expands pathnames of sockets if relative to "~" or "~username"
  514. # expands "*:port and ":port" to "0.0.0.0:port"
  515. def expand_addr(address) #:nodoc:
  516. return "0.0.0.0:#{address}" if Integer === address
  517. return address unless String === address
  518. case address
  519. when %r{\Aunix:(.*)\z}
  520. File.expand_path($1)
  521. when %r{\A~}
  522. File.expand_path(address)
  523. when %r{\A(?:\*:)?(\d+)\z}
  524. "0.0.0.0:#$1"
  525. when %r{\A\[([a-fA-F0-9:]+)\]\z}, %r/\A((?:\d+\.){3}\d+)\z/
  526. canonicalize_tcp($1, 80)
  527. when %r{\A\[([a-fA-F0-9:]+)\]:(\d+)\z}, %r{\A(.*):(\d+)\z}
  528. canonicalize_tcp($1, $2.to_i)
  529. else
  530. address
  531. end
  532. end
  533. private
  534. def set_int(var, n, min) #:nodoc:
  535. Integer === n or raise ArgumentError, "not an integer: #{var}=#{n.inspect}"
  536. n >= min or raise ArgumentError, "too low (< #{min}): #{var}=#{n.inspect}"
  537. set[var] = n
  538. end
  539. def canonicalize_tcp(addr, port)
  540. packed = Socket.pack_sockaddr_in(port, addr)
  541. port, addr = Socket.unpack_sockaddr_in(packed)
  542. /:/ =~ addr ? "[#{addr}]:#{port}" : "#{addr}:#{port}"
  543. end
  544. def set_path(var, path) #:nodoc:
  545. case path
  546. when NilClass, String
  547. set[var] = path
  548. else
  549. raise ArgumentError
  550. end
  551. end
  552. def check_bool(var, bool) # :nodoc:
  553. case bool
  554. when true, false
  555. return bool
  556. end
  557. raise ArgumentError, "#{var}=#{bool.inspect} not a boolean"
  558. end
  559. def set_bool(var, bool) #:nodoc:
  560. set[var] = check_bool(var, bool)
  561. end
  562. def set_hook(var, my_proc, req_arity = 2) #:nodoc:
  563. case my_proc
  564. when Proc
  565. arity = my_proc.arity
  566. (arity == req_arity) or \
  567. raise ArgumentError,
  568. "#{var}=#{my_proc.inspect} has invalid arity: " \
  569. "#{arity} (need #{req_arity})"
  570. when NilClass
  571. my_proc = DEFAULTS[var]
  572. else
  573. raise ArgumentError, "invalid type: #{var}=#{my_proc.inspect}"
  574. end
  575. set[var] = my_proc
  576. end
  577. # this is called _after_ working_directory is bound. This only
  578. # parses the embedded switches in .ru files
  579. # (for "rackup" compatibility)
  580. def parse_rackup_file # :nodoc:
  581. ru = RACKUP[:file] or return # we only return here in unit tests
  582. # :rails means use (old) Rails autodetect
  583. if ru == :rails
  584. File.readable?('config.ru') or return
  585. ru = 'config.ru'
  586. end
  587. File.readable?(ru) or
  588. raise ArgumentError, "rackup file (#{ru}) not readable"
  589. # it could be a .rb file, too, we don't parse those manually
  590. ru =~ /\.ru\z/ or return
  591. /^#\\(.*)/ =~ File.read(ru) or return
  592. RACKUP[:optparse].parse!($1.split(/\s+/))
  593. if RACKUP[:daemonize]
  594. # unicorn_rails wants a default pid path, (not plain 'unicorn')
  595. if after_reload
  596. spid = set[:pid]
  597. pid('tmp/pids/unicorn.pid') if spid.nil? || spid == :unset
  598. end
  599. unless RACKUP[:daemonized]
  600. Unicorn::Launcher.daemonize!(RACKUP[:options])
  601. RACKUP[:ready_pipe] = RACKUP[:options].delete(:ready_pipe)
  602. end
  603. end
  604. end
  605. end