pitchfork 0.13.0 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,40 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'raindrops'
4
-
5
3
  module Pitchfork
6
4
  module SharedMemory
7
5
  extend self
8
6
 
9
- PER_DROP = Raindrops::PAGE_SIZE / Raindrops::SIZE
10
7
  CURRENT_GENERATION_OFFSET = 0
11
8
  SHUTDOWN_OFFSET = 1
12
9
  MOLD_TICK_OFFSET = 2
13
10
  MOLD_PROMOTION_TICK_OFFSET = 3
14
- WORKER_TICK_OFFSET = 4
11
+ SERVICE_TICK_OFFSET = 4
12
+ WORKER_TICK_OFFSET = 5
15
13
 
16
- DROPS = [Raindrops.new(PER_DROP)]
14
+ PAGES = [MemoryPage.new(MemoryPage::SLOTS)]
17
15
 
18
16
  def current_generation
19
- DROPS[0][CURRENT_GENERATION_OFFSET]
17
+ PAGES[0][CURRENT_GENERATION_OFFSET]
20
18
  end
21
19
 
22
20
  def current_generation=(value)
23
- DROPS[0][CURRENT_GENERATION_OFFSET] = value
21
+ PAGES[0][CURRENT_GENERATION_OFFSET] = value
24
22
  end
25
23
 
26
24
  def shutting_down!
27
- DROPS[0][SHUTDOWN_OFFSET] = 1
25
+ PAGES[0][SHUTDOWN_OFFSET] = 1
28
26
  end
29
27
 
30
28
  def shutting_down?
31
- DROPS[0][SHUTDOWN_OFFSET] > 0
29
+ PAGES[0][SHUTDOWN_OFFSET] > 0
32
30
  end
33
31
 
34
32
  class Field
35
33
  def initialize(offset)
36
- @drop = DROPS.fetch(offset / PER_DROP)
37
- @offset = offset % PER_DROP
34
+ @drop = PAGES.fetch(offset / MemoryPage::SLOTS)
35
+ @offset = offset % MemoryPage::SLOTS
38
36
  end
39
37
 
40
38
  def value
@@ -54,6 +52,10 @@ module Pitchfork
54
52
  self[MOLD_PROMOTION_TICK_OFFSET]
55
53
  end
56
54
 
55
+ def service_deadline
56
+ self[SERVICE_TICK_OFFSET]
57
+ end
58
+
57
59
  def worker_deadline(worker_nr)
58
60
  self[WORKER_TICK_OFFSET + worker_nr]
59
61
  end
@@ -67,9 +69,9 @@ module Pitchfork
67
69
  #
68
70
  # However this doesn't account for TTIN signals that increase the
69
71
  # number of workers, but we should probably remove that feature too.
70
- def preallocate_drops(workers_count)
71
- 0.upto(((WORKER_TICK_OFFSET + workers_count) / PER_DROP.to_f).ceil) do |i|
72
- DROPS[i] ||= Raindrops.new(PER_DROP)
72
+ def preallocate_pages(workers_count)
73
+ 0.upto(((WORKER_TICK_OFFSET + workers_count) / MemoryPage::SLOTS.to_f).ceil) do |i|
74
+ PAGES[i] ||= MemoryPage.new(MemoryPage::SLOTS)
73
75
  end
74
76
  end
75
77
  end
@@ -72,7 +72,7 @@ module Pitchfork
72
72
  rescue => e
73
73
  logger.error("#{sock_name(sock)} " \
74
74
  "failed to set accept_filter=#{name} (#{e.inspect})")
75
- logger.error("perhaps accf_http(9) needs to be loaded".freeze)
75
+ logger.error("perhaps accf_http(9) needs to be loaded")
76
76
  end if arg != got
77
77
  end
78
78
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pitchfork
4
- VERSION = "0.13.0"
4
+ VERSION = "0.14.0"
5
5
  module Const
6
6
  UNICORN_VERSION = '6.1.0'
7
7
  end
@@ -6,7 +6,7 @@ module Pitchfork
6
6
  # This class and its members can be considered a stable interface
7
7
  # and will not change in a backwards-incompatible fashion between
8
8
  # releases of pitchfork. Knowledge of this class is generally not
9
- # not needed for most users of pitchfork.
9
+ # needed for most users of pitchfork.
10
10
  #
11
11
  # Some users may want to access it in the after_worker_fork/after_mold_fork hooks.
12
12
  # See the Pitchfork::Configurator RDoc for examples.
@@ -24,20 +24,7 @@ module Pitchfork
24
24
  @to_io = @master = nil
25
25
  @exiting = false
26
26
  @requests_count = 0
27
- if nr
28
- @deadline_drop = SharedMemory.worker_deadline(nr)
29
- self.deadline = 0
30
- else
31
- promoted!(nil)
32
- end
33
- end
34
-
35
- def meminfo
36
- @meminfo ||= MemInfo.new(pid) if pid
37
- end
38
-
39
- def refresh
40
- meminfo&.update
27
+ init_deadline
41
28
  end
42
29
 
43
30
  def exiting?
@@ -94,6 +81,10 @@ module Pitchfork
94
81
  send_message_nonblock(Message::SpawnWorker.new(new_worker.nr))
95
82
  end
96
83
 
84
+ def spawn_service(_new_service)
85
+ send_message_nonblock(Message::SpawnService.new)
86
+ end
87
+
97
88
  def promote!(timeout)
98
89
  @generation += 1
99
90
  promoted!(timeout)
@@ -111,6 +102,10 @@ module Pitchfork
111
102
  @mold
112
103
  end
113
104
 
105
+ def service?
106
+ false
107
+ end
108
+
114
109
  def to_io # IO.select-compatible
115
110
  @to_io.to_io
116
111
  end
@@ -220,6 +215,15 @@ module Pitchfork
220
215
 
221
216
  private
222
217
 
218
+ def init_deadline
219
+ if nr
220
+ @deadline_drop = SharedMemory.worker_deadline(@nr)
221
+ self.deadline = 0
222
+ else
223
+ promoted!(nil)
224
+ end
225
+ end
226
+
223
227
  def pipe=(socket)
224
228
  raise ArgumentError, "pipe can't be nil" unless socket
225
229
  Info.keep_io(socket)
@@ -241,4 +245,28 @@ module Pitchfork
241
245
  success
242
246
  end
243
247
  end
248
+
249
+ class Service < Worker
250
+ def initialize(pid: nil, generation: 0)
251
+ super(nil, pid: pid, generation: generation)
252
+ end
253
+
254
+ def service?
255
+ true
256
+ end
257
+
258
+ def register_to_master(control_socket)
259
+ create_socketpair!
260
+ message = Message::ServiceSpawned.new(@pid, generation, @master)
261
+ control_socket.sendmsg(message)
262
+ @master.close
263
+ end
264
+
265
+ private
266
+
267
+ def init_deadline
268
+ @deadline_drop = SharedMemory.service_deadline
269
+ self.deadline = 0
270
+ end
271
+ end
244
272
  end
data/lib/pitchfork.rb CHANGED
@@ -2,7 +2,6 @@
2
2
  # frozen_string_literal: true
3
3
  require 'etc'
4
4
  require 'stringio'
5
- require 'raindrops'
6
5
  require 'io/wait'
7
6
 
8
7
  begin
@@ -120,25 +119,6 @@ module Pitchfork
120
119
  exc.backtrace.each { |line| logger.error(line) }
121
120
  end
122
121
 
123
- F_SETPIPE_SZ = 1031 if RUBY_PLATFORM =~ /linux/
124
-
125
- def pipe # :nodoc:
126
- IO.pipe.each do |io|
127
- # shrink pipes to minimize impact on /proc/sys/fs/pipe-user-pages-soft
128
- # limits.
129
- if defined?(F_SETPIPE_SZ)
130
- begin
131
- io.fcntl(F_SETPIPE_SZ, Raindrops::PAGE_SIZE)
132
- rescue Errno::EINVAL
133
- # old kernel
134
- rescue Errno::EPERM
135
- # resizes fail if Linux is close to the pipe limit for the user
136
- # or if the user does not have permissions to resize
137
- end
138
- end
139
- end
140
- end
141
-
142
122
  def socketpair
143
123
  pair = UNIXSocket.socketpair(@socket_type).map { |s| MessageSocket.new(s) }
144
124
  pair[0].close_write
data/pitchfork.gemspec CHANGED
@@ -19,7 +19,6 @@ Gem::Specification.new do |s|
19
19
 
20
20
  s.required_ruby_version = ">= 2.5.0"
21
21
 
22
- s.add_dependency(%q<raindrops>, '~> 0.7')
23
22
  s.add_dependency(%q<rack>, '>= 2.0')
24
23
 
25
24
  # Note: To avoid ambiguity, we intentionally avoid the SPDX-compatible
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pitchfork
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean Boussier
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-04-08 00:00:00.000000000 Z
11
+ date: 2024-05-29 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: raindrops
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '0.7'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '0.7'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: rack
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -54,6 +40,7 @@ files:
54
40
  - ".gitattributes"
55
41
  - ".github/workflows/ci.yml"
56
42
  - ".gitignore"
43
+ - ".ruby-version"
57
44
  - CHANGELOG.md
58
45
  - COPYING
59
46
  - Dockerfile
@@ -68,6 +55,7 @@ files:
68
55
  - docs/CONFIGURATION.md
69
56
  - docs/DESIGN.md
70
57
  - docs/FORK_SAFETY.md
58
+ - docs/MIGRATING_FROM_UNICORN.md
71
59
  - docs/PHILOSOPHY.md
72
60
  - docs/REFORKING.md
73
61
  - docs/SIGNALS.md
@@ -79,6 +67,7 @@ files:
79
67
  - examples/nginx.conf
80
68
  - examples/pitchfork.conf.minimal.rb
81
69
  - examples/pitchfork.conf.rb
70
+ - examples/pitchfork.conf.service.rb
82
71
  - examples/unicorn.socket
83
72
  - exe/pitchfork
84
73
  - ext/pitchfork_http/CFLAGS
@@ -90,11 +79,11 @@ files:
90
79
  - ext/pitchfork_http/extconf.rb
91
80
  - ext/pitchfork_http/global_variables.h
92
81
  - ext/pitchfork_http/httpdate.c
82
+ - ext/pitchfork_http/memory_page.c
93
83
  - ext/pitchfork_http/pitchfork_http.c
94
84
  - ext/pitchfork_http/pitchfork_http.rl
95
85
  - ext/pitchfork_http/pitchfork_http_common.rl
96
86
  - lib/pitchfork.rb
97
- - lib/pitchfork/app/old_rails/static.rb
98
87
  - lib/pitchfork/children.rb
99
88
  - lib/pitchfork/chunked.rb
100
89
  - lib/pitchfork/configurator.rb
@@ -138,7 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
138
127
  - !ruby/object:Gem::Version
139
128
  version: '0'
140
129
  requirements: []
141
- rubygems_version: 3.5.5
130
+ rubygems_version: 3.5.9
142
131
  signing_key:
143
132
  specification_version: 4
144
133
  summary: Rack HTTP server for fast clients and Unix
@@ -1,60 +0,0 @@
1
- # -*- encoding: binary -*-
2
- # frozen_string_literal: true
3
- # :enddoc:
4
- # This code is based on the original Rails handler in Mongrel
5
- # Copyright (c) 2005 Zed A. Shaw
6
- # Copyright (c) 2009 Eric Wong
7
- # You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
8
- # the GPLv3
9
-
10
- # Static file handler for Rails < 2.3. This handler is only provided
11
- # as a convenience for developers. Performance-minded deployments should
12
- # use nginx (or similar) for serving static files.
13
- #
14
- # This supports page caching directly and will try to resolve a
15
- # request in the following order:
16
- #
17
- # * If the requested exact PATH_INFO exists as a file then serve it.
18
- # * If it exists at PATH_INFO+rest_operator+".html" exists
19
- # then serve that.
20
- #
21
- # This means that if you are using page caching it will actually work
22
- # with Pitchfork and you should see a decent speed boost (but not as
23
- # fast as if you use a static server like nginx).
24
- class Pitchfork::App::OldRails::Static < Struct.new(:app, :root, :file_server)
25
- FILE_METHODS = { 'GET' => true, 'HEAD' => true }
26
-
27
- # avoid allocating new strings for hash lookups
28
- REQUEST_METHOD = 'REQUEST_METHOD'
29
- REQUEST_URI = 'REQUEST_URI'
30
- PATH_INFO = 'PATH_INFO'
31
-
32
- def initialize(app)
33
- self.app = app
34
- self.root = "#{::RAILS_ROOT}/public"
35
- self.file_server = ::Rack::File.new(root)
36
- end
37
-
38
- def call(env)
39
- # short circuit this ASAP if serving non-file methods
40
- FILE_METHODS.include?(env[REQUEST_METHOD]) or return app.call(env)
41
-
42
- # first try the path as-is
43
- path_info = env[PATH_INFO].chomp("/")
44
- if File.file?("#{root}/#{::Rack::Utils.unescape(path_info)}")
45
- # File exists as-is so serve it up
46
- env[PATH_INFO] = path_info
47
- return file_server.call(env)
48
- end
49
-
50
- # then try the cached version:
51
- path_info << ActionController::Base.page_cache_extension
52
-
53
- if File.file?("#{root}/#{::Rack::Utils.unescape(path_info)}")
54
- env[PATH_INFO] = path_info
55
- return file_server.call(env)
56
- end
57
-
58
- app.call(env) # call OldRails
59
- end
60
- end if defined?(Pitchfork::App::OldRails)