pitchfork 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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)