pitchfork 0.1.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.

Potentially problematic release.


This version of pitchfork might be problematic. Click here for more details.

Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/.git-blame-ignore-revs +3 -0
  3. data/.gitattributes +5 -0
  4. data/.github/workflows/ci.yml +30 -0
  5. data/.gitignore +23 -0
  6. data/COPYING +674 -0
  7. data/Dockerfile +4 -0
  8. data/Gemfile +9 -0
  9. data/Gemfile.lock +30 -0
  10. data/LICENSE +67 -0
  11. data/README.md +123 -0
  12. data/Rakefile +72 -0
  13. data/docs/Application_Timeouts.md +74 -0
  14. data/docs/CONFIGURATION.md +388 -0
  15. data/docs/DESIGN.md +86 -0
  16. data/docs/FORK_SAFETY.md +80 -0
  17. data/docs/PHILOSOPHY.md +90 -0
  18. data/docs/REFORKING.md +113 -0
  19. data/docs/SIGNALS.md +38 -0
  20. data/docs/TUNING.md +106 -0
  21. data/examples/constant_caches.ru +43 -0
  22. data/examples/echo.ru +25 -0
  23. data/examples/hello.ru +5 -0
  24. data/examples/nginx.conf +156 -0
  25. data/examples/pitchfork.conf.minimal.rb +5 -0
  26. data/examples/pitchfork.conf.rb +77 -0
  27. data/examples/unicorn.socket +11 -0
  28. data/exe/pitchfork +116 -0
  29. data/ext/pitchfork_http/CFLAGS +13 -0
  30. data/ext/pitchfork_http/c_util.h +116 -0
  31. data/ext/pitchfork_http/child_subreaper.h +25 -0
  32. data/ext/pitchfork_http/common_field_optimization.h +130 -0
  33. data/ext/pitchfork_http/epollexclusive.h +124 -0
  34. data/ext/pitchfork_http/ext_help.h +38 -0
  35. data/ext/pitchfork_http/extconf.rb +14 -0
  36. data/ext/pitchfork_http/global_variables.h +97 -0
  37. data/ext/pitchfork_http/httpdate.c +79 -0
  38. data/ext/pitchfork_http/pitchfork_http.c +4318 -0
  39. data/ext/pitchfork_http/pitchfork_http.rl +1024 -0
  40. data/ext/pitchfork_http/pitchfork_http_common.rl +76 -0
  41. data/lib/pitchfork/app/old_rails/static.rb +59 -0
  42. data/lib/pitchfork/children.rb +124 -0
  43. data/lib/pitchfork/configurator.rb +314 -0
  44. data/lib/pitchfork/const.rb +23 -0
  45. data/lib/pitchfork/http_parser.rb +206 -0
  46. data/lib/pitchfork/http_response.rb +63 -0
  47. data/lib/pitchfork/http_server.rb +822 -0
  48. data/lib/pitchfork/launcher.rb +9 -0
  49. data/lib/pitchfork/mem_info.rb +36 -0
  50. data/lib/pitchfork/message.rb +130 -0
  51. data/lib/pitchfork/mold_selector.rb +29 -0
  52. data/lib/pitchfork/preread_input.rb +33 -0
  53. data/lib/pitchfork/refork_condition.rb +21 -0
  54. data/lib/pitchfork/select_waiter.rb +9 -0
  55. data/lib/pitchfork/socket_helper.rb +199 -0
  56. data/lib/pitchfork/stream_input.rb +152 -0
  57. data/lib/pitchfork/tee_input.rb +133 -0
  58. data/lib/pitchfork/tmpio.rb +35 -0
  59. data/lib/pitchfork/version.rb +8 -0
  60. data/lib/pitchfork/worker.rb +244 -0
  61. data/lib/pitchfork.rb +158 -0
  62. data/pitchfork.gemspec +30 -0
  63. metadata +137 -0
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem 'minitest'
6
+ gem 'rake'
7
+ gem 'rake-compiler'
8
+
9
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,30 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ pitchfork (0.1.0)
5
+ rack (>= 2.0)
6
+ raindrops (~> 0.7)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ minitest (5.16.3)
12
+ rack (3.0.0)
13
+ raindrops (0.20.0)
14
+ rake (13.0.6)
15
+ rake-compiler (1.2.0)
16
+ rake
17
+
18
+ PLATFORMS
19
+ aarch64-linux
20
+ arm64-darwin-21
21
+ x86_64-linux
22
+
23
+ DEPENDENCIES
24
+ minitest
25
+ pitchfork!
26
+ rake
27
+ rake-compiler
28
+
29
+ BUNDLED WITH
30
+ 2.3.22
data/LICENSE ADDED
@@ -0,0 +1,67 @@
1
+ Unicorn is copyrighted free software by all contributors, see logs in
2
+ revision control for names and email addresses of all of them.
3
+
4
+ You can redistribute it and/or modify it under either the terms of the
5
+ GNU General Public License (GPL) as published by the Free Software
6
+ Foundation (FSF), either version 2 of the License, or (at your option)
7
+ any later version. We currently prefer the GPLv3 or later for
8
+ derivative works, but the GPLv2 is fine.
9
+
10
+ The complete texts of the GPLv2 and GPLv3 are below:
11
+ GPLv2 - https://www.gnu.org/licenses/gpl-2.0.txt
12
+ GPLv3 - https://www.gnu.org/licenses/gpl-3.0.txt
13
+
14
+ You may (against our _preference_) also use the Ruby 1.8 license terms
15
+ which we inherited from the original Mongrel project when we forked it:
16
+
17
+ === Ruby 1.8-specific terms (if you're not using the GPL)
18
+
19
+ 1. You may make and give away verbatim copies of the source form of the
20
+ software without restriction, provided that you duplicate all of the
21
+ original copyright notices and associated disclaimers.
22
+
23
+ 2. You may modify your copy of the software in any way, provided that
24
+ you do at least ONE of the following:
25
+
26
+ a) place your modifications in the Public Domain or otherwise make them
27
+ Freely Available, such as by posting said modifications to Usenet or an
28
+ equivalent medium, or by allowing the author to include your
29
+ modifications in the software.
30
+
31
+ b) use the modified software only within your corporation or
32
+ organization.
33
+
34
+ c) rename any non-standard executables so the names do not conflict with
35
+ standard executables, which must also be provided.
36
+
37
+ d) make other distribution arrangements with the author.
38
+
39
+ 3. You may distribute the software in object code or executable
40
+ form, provided that you do at least ONE of the following:
41
+
42
+ a) distribute the executables and library files of the software,
43
+ together with instructions (in the manual page or equivalent) on where
44
+ to get the original distribution.
45
+
46
+ b) accompany the distribution with the machine-readable source of the
47
+ software.
48
+
49
+ c) give non-standard executables non-standard names, with
50
+ instructions on where to get the original software distribution.
51
+
52
+ d) make other distribution arrangements with the author.
53
+
54
+ 4. You may modify and include the part of the software into any other
55
+ software (possibly commercial). But some files in the distribution
56
+ are not written by the author, so that they are not under this terms.
57
+
58
+ 5. The scripts and library files supplied as input to or produced as
59
+ output from the software do not automatically fall under the
60
+ copyright of the software, but belong to whomever generated them,
61
+ and may be sold commercially, and may be aggregated with this
62
+ software.
63
+
64
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
65
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
66
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
67
+ PURPOSE.
data/README.md ADDED
@@ -0,0 +1,123 @@
1
+ # pitchfork: Rack HTTP server for shared-nothing architecture
2
+
3
+ `pitchfork` is a preforking HTTP server for Rack applications designed
4
+ to minimize memory usage by maximizing Copy-on-Write performance.
5
+
6
+ Like [`unicorn`](https://yhbt.net/unicorn/README.html) (which `pitchfork` is a derivative of), is it designed to
7
+ only serve fast clients on low-latency, high-bandwidth connections and take
8
+ advantage of features in Unix/Unix-like kernels. Slow clients should
9
+ only be served by placing a reverse proxy capable of fully buffering
10
+ both the request and response in between `pitchfork` and slow clients.
11
+
12
+ ## Disclaimer
13
+
14
+ Until this notice is removed from the README, `pitchfork` should be
15
+ considered experimental. As such it is not encouraged to run it in
16
+ production just yet unless you feel capable of debugging yourself
17
+ any issue that may arise.
18
+
19
+ ## Features
20
+
21
+ * Designed for Rack, Linux, fast clients, and ease-of-debugging. We
22
+ cut out everything that is better supported by the operating system,
23
+ [nginx](https://nginx.org/) or [Rack](https://rack.github.io/).
24
+
25
+ * Shared-Nothing architecture: workers all run within their own isolated
26
+ address space and only serve one client at a time for maximum performance
27
+ and robustness. Concurrent requests don't need to compete for the GVL,
28
+ or impact each others latency when triggering garbage collection.
29
+ It also does not care if your application is thread-safe or not.
30
+
31
+ * Reforking: `pitchfork` can be configured to periodically promote a warmed up worker
32
+ as the new template from which workers are forked. This dramatically improves
33
+ the proportion of shared memory, making processes use only marginally more
34
+ memory than threads would.
35
+
36
+ * Compatible with Ruby 2.5.0 and later.
37
+
38
+ * Process management: `pitchfork` will reap and restart workers that
39
+ die from broken apps. There is no need to manage multiple processes
40
+ or ports yourself. `pitchfork` can spawn and manage any number of
41
+ worker processes you choose to scale to your backend.
42
+
43
+ * Load balancing is done entirely by the operating system kernel.
44
+ Requests never pile up behind a busy worker process.
45
+
46
+ ## Requirements
47
+
48
+ Ruby(MRI) Version 2.5 and above.
49
+
50
+ `pitchfork` can be used on any Unix-like system, however the reforking
51
+ feature requires `PR_SET_CHILD_SUBREAPER` which is a Linux 3.4 (May 2012) feature.
52
+
53
+ ## Installation
54
+
55
+ Add this line to your application's Gemfile:
56
+
57
+ ```ruby
58
+ gem "pitchfork"
59
+ ```
60
+
61
+ And then execute:
62
+
63
+ ```bash
64
+ $ bundle install
65
+ ```
66
+
67
+ Or install it yourself as:
68
+
69
+ ```
70
+ $ gem install pitchfork
71
+ ```
72
+
73
+ ## Usage
74
+
75
+ ### Rack
76
+
77
+ In your application root directory, run:
78
+
79
+ ```bash
80
+ $ bundle exec pitchfork
81
+ ```
82
+
83
+ `pitchfork` will bind to all interfaces on TCP port 8080 by default.
84
+ You may use the `--listen` switch to bind to a different
85
+ address:port or a UNIX socket.
86
+
87
+ ### Configuration File(s)
88
+
89
+ `pitchfork` will look for the config.ru file used by rackup in APP_ROOT.
90
+
91
+ For deployments, it can use a config file for pitchfork-specific options
92
+ specified by the `--config-file/-c` command-line switch.
93
+ See the [configuration documentation](docs/CONFIGURATION.md) for the syntax
94
+ of the pitchfork-specific options.
95
+
96
+ The default settings are designed for maximum out-of-the-box
97
+ compatibility with existing applications.
98
+
99
+ Most command-line options for other Rack applications (above) are also
100
+ supported. Run `pitchfork -h` to see command-line options.
101
+
102
+ ## License
103
+
104
+ pitchfork is copyright 2022 Shopify Inc and all contributors.
105
+ It is based on Unicorn 6.1.0.
106
+
107
+ Unicorn is copyright 2009-2018 by all contributors (see logs in git).
108
+ It is based on Mongrel 1.1.5.
109
+ Mongrel is copyright 2007 Zed A. Shaw and contributors.
110
+
111
+ pitchfork is licensed under (your choice) of the GPLv2 or later
112
+ (GPLv3+ preferred), or Ruby (1.8)-specific terms.
113
+ See the included LICENSE file for details.
114
+
115
+ ## Thanks
116
+
117
+ Thanks to Eric Wong and all Unicorn and Mongrel contributors over the years.
118
+ Pitchfork would have been much harder to implement otherwise.
119
+
120
+ Thanks to Will Jordan who implemented Puma's "fork worker" experimental feature
121
+ which have been a significant inspiration for Pitchfork.
122
+
123
+ Thanks to Peter Bui for letting us use the `pitchfork` name on Rubygems.
data/Rakefile ADDED
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+ require "bundler/gem_tasks"
3
+ require "rake/testtask"
4
+ require "rake/extensiontask"
5
+
6
+ Rake::TestTask.new("test:unit") do |t|
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/unit/**/test_*.rb"]
10
+ t.options = '-v' if ENV['CI'] || ENV['VERBOSE']
11
+ t.warning = true
12
+ end
13
+
14
+ namespace :test do
15
+ # It's not so much that these tests are slow, but they tend to fork
16
+ # and/or register signal handlers, so they if something goes wrong
17
+ # they are likely to get stuck forever.
18
+ # The unicorn test suite has historically ran them in individual process
19
+ # so we continue to do that.
20
+ task slow: :compile do
21
+ tests = Dir["test/slow/**/*.rb"].flat_map do |test_file|
22
+ File.read(test_file).scan(/def (test_\w+)/).map do |test|
23
+ [test_file] + test
24
+ end
25
+ end
26
+ tests.each do |file, test|
27
+ sh "ruby", "-Ilib:test", file, "-n", test, "-v"
28
+ end
29
+ end
30
+
31
+ # Unicorn had its own POSIX-shell based testing framework.
32
+ # It's quite hard to work with and it would be good to convert all this
33
+ # to Ruby integration tests, but while pitchfork is a moving target it's
34
+ # preferable to edit the test suite as little as possible.
35
+ task integration: :compile do
36
+ File.write("test/integration/random_blob", File.read("/dev/random", 1_000_000))
37
+ lib = File.expand_path("lib", __dir__)
38
+ path = "#{File.expand_path("exe", __dir__)}:#{ENV["PATH"]}"
39
+ old_path = ENV["PATH"]
40
+ ENV["PATH"] = "#{path}:#{old_path}"
41
+ begin
42
+ Dir.chdir("test/integration") do
43
+ Dir["t[0-9]*.sh"].each do |integration_test|
44
+ sh("rm", "-rf", "trash")
45
+ sh("mkdir", "trash")
46
+ command = ["sh", integration_test]
47
+ command << "-v" if ENV["VERBOSE"] || ENV["CI"]
48
+ sh(*command)
49
+ end
50
+ end
51
+ ensure
52
+ ENV["PATH"] = old_path
53
+ end
54
+ end
55
+ end
56
+
57
+ Rake::ExtensionTask.new("pitchfork_http") do |ext|
58
+ ext.ext_dir = 'ext/pitchfork_http'
59
+ ext.lib_dir = 'lib/pitchfork'
60
+ end
61
+
62
+ task :ragel do
63
+ Dir.chdir(File.expand_path("ext/pitchfork_http", __dir__)) do
64
+ puts "* compiling pitchfork_http.rl"
65
+ cmd = ["ragel", "-G2", "pitchfork_http.rl", "-o", "pitchfork_http.c"]
66
+ system(*cmd) or raise "== #{cmd.join(' ')} failed =="
67
+ end
68
+ end
69
+
70
+ task test: %i(test:unit test:slow test:integration)
71
+
72
+ task default: %i(ragel compile test)
@@ -0,0 +1,74 @@
1
+ # Application Timeouts
2
+
3
+ This article focuses on _application_ setup for Rack applications, but
4
+ can be expanded to all applications that connect to external resources
5
+ and expect short response times.
6
+
7
+ This article is not specific to `pitchfork`, but exists to discourage
8
+ the overuse of the built-in `timeout` directive in `pitchfork`.
9
+
10
+ ## ALL External Resources Are Considered Unreliable
11
+
12
+ Network reliability can _never_ be guaranteed. Network failures cannot
13
+ be detected reliably by the client (Rack application) in a reasonable
14
+ timeframe, not even on a LAN.
15
+
16
+ Thus, application authors must configure timeouts when interacting with
17
+ external resources.
18
+
19
+ Most database adapters allow configurable timeouts.
20
+
21
+ `Net::HTTP` and `Net::SMTP` in the Ruby standard library allow
22
+ configurable timeouts.
23
+
24
+ Even for things as fast as [memcached](https://memcached.org/),
25
+ [dalli](https://rubygems.org/gems/dalli) and other memcached clients,
26
+ all offer configurable timeouts.
27
+
28
+ Consult the relevant documentation for the libraries you use on
29
+ how to configure these timeouts.
30
+
31
+ ## Timeout module in the Ruby standard library
32
+
33
+ Ruby offers a Timeout module in its standard library. It has several
34
+ caveats and is not always reliable:
35
+
36
+ * /Some/ Ruby C extensions are not interrupted/timed-out gracefully by
37
+ this module (report these bugs to extension authors, please) but
38
+ pure-Ruby components should be.
39
+
40
+ * `Timeout` uses [`Thread#raise` which most code don't and probably can't
41
+ handle properly](https://www.mikeperham.com/2015/05/08/timeout-rubys-most-dangerous-api/).
42
+ A process in which a `Timeout.timeout` block expired
43
+ should be considered corrupted and should exit as soon as possible.
44
+
45
+ * Long-running tasks may run inside `ensure' clauses after timeout
46
+ fires, causing the timeout to be ineffective.
47
+
48
+ The Timeout module is a second-to-last-resort solution, timeouts using
49
+ `IO.select` (or similar) are more reliable. If you depend on libraries
50
+ that do not offer timeouts when connecting to external resources, kindly
51
+ ask those library authors to provide configurable timeouts.
52
+
53
+ ### A Note About Filesystems
54
+
55
+ Most operations to regular files on POSIX filesystems are NOT
56
+ interruptible. Thus, the "timeout" module in the Ruby standard library
57
+ can not reliably timeout systems with massive amounts of iowait.
58
+
59
+ If your app relies on the filesystem, ensure all the data your
60
+ application works with is small enough to fit in the kernel page cache.
61
+ Otherwise increase the amount of physical memory you have to match, or
62
+ employ a fast, low-latency storage system (solid state).
63
+
64
+ Volumes mounted over NFS (and thus a potentially unreliable network)
65
+ must be mounted with timeouts and applications must be prepared to
66
+ handle network/server failures.
67
+
68
+ ## The Last Line Of Defense
69
+
70
+ The `timeout` mechanism in pitchfork is an extreme solution that should
71
+ be avoided whenever possible.
72
+ It will help preserve the platform if your application or a dependency
73
+ has a bug that cause it to either get stuck or two slow, but it is not a
74
+ solution to such bugs, merely a mitigation.