grpc_fork_safety 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.
- checksums.yaml +7 -0
- data/.rubocop.yml +28 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +5 -0
- data/README.md +59 -0
- data/Rakefile +12 -0
- data/lib/grpc_fork_safety/init.rb +15 -0
- data/lib/grpc_fork_safety/no_patch.rb +140 -0
- data/lib/grpc_fork_safety/patch.rb +20 -0
- data/lib/grpc_fork_safety/version.rb +5 -0
- data/lib/grpc_fork_safety.rb +5 -0
- metadata +70 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: cf32a7caf75ba7c10da05f6a07eb4fb071d8d1242947be0006d7c80d0789542e
|
4
|
+
data.tar.gz: d999967eb9c841a40ea919f507ed9e2c5eaaf17909ca6614ffe5686317b2bc25
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 630e682ecaaf7352ae3a7db2db4e3768f348e52fa06ed1d906743ae07caced67af02ec0d231846ea6016983bbe0dff3cb52f065da389c89c0ee8908c6ac2a573
|
7
|
+
data.tar.gz: 2f9c820ab4004b05dd5f752ca02557e3e92818dcbd959fe067758203d37dc4b10da04bd76070de1da298fb5ae9cc6507bd611a2830e65c3758f56253f29385df
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 3.1
|
3
|
+
SuggestExtensions: false
|
4
|
+
NewCops: enable
|
5
|
+
|
6
|
+
Style/StringLiterals:
|
7
|
+
EnforcedStyle: double_quotes
|
8
|
+
|
9
|
+
Style/StringLiteralsInInterpolation:
|
10
|
+
EnforcedStyle: double_quotes
|
11
|
+
|
12
|
+
Style/Documentation:
|
13
|
+
Enabled: false
|
14
|
+
|
15
|
+
Style/IfUnlessModifier:
|
16
|
+
Enabled: false
|
17
|
+
|
18
|
+
Gemspec/RequireMFA:
|
19
|
+
Enabled: false
|
20
|
+
|
21
|
+
Metrics/MethodLength:
|
22
|
+
Enabled: false
|
23
|
+
|
24
|
+
Metrics/AbcSize:
|
25
|
+
Enabled: false
|
26
|
+
|
27
|
+
Metrics/ClassLength:
|
28
|
+
Enabled: false
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.3.3
|
data/CHANGELOG.md
ADDED
data/README.md
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# GrpcForkSafety
|
2
|
+
|
3
|
+
Small gem that makes it easier to use the `grpc` gem in a fork safe way.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add the gem to your gemfile **before the `grpc` gem, or any gem that depend on `grpc`:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem "grpc_fork_safety"
|
11
|
+
gem "grpc"
|
12
|
+
gem "some-gem-that-depend-on-grpc"
|
13
|
+
```
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
There isn't anything particular to do, the gem will hook itself into Ruby and properly call the GRPC fork hooks when needed.
|
18
|
+
|
19
|
+
### `keep_disabled!`
|
20
|
+
|
21
|
+
However, when a process will need to fork repeatedly and won't need to use GRPC, you can optimize by calling `GrpcForkSafety.keep_disabled!`.
|
22
|
+
`grpc` will be enabled again in child process, but stay shutdown in the current process. This is useful for the main process of Puma or Unicorn
|
23
|
+
and for the mold process of Pitchfork, e.g.
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
before_fork do
|
27
|
+
GrpcForkSafety.keep_disabled!
|
28
|
+
end
|
29
|
+
```
|
30
|
+
|
31
|
+
If for some reason you need to undo this, you can call `GrpcForkSafety.reenable!`
|
32
|
+
|
33
|
+
### Hooks
|
34
|
+
|
35
|
+
You can also register hooks to be called before GRPC is disabled and after it's re-enabled:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
GrpcForkSafety.before_disable do
|
39
|
+
ThreadPool.shutdown
|
40
|
+
end
|
41
|
+
|
42
|
+
GrpcForkSafety.after_enable do |in_child|
|
43
|
+
unless in_child
|
44
|
+
ThreadPool.start
|
45
|
+
end
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
Typically if you have background threads using GRPC, you should make sure to shut them down in `before_disable`.
|
50
|
+
|
51
|
+
## Development
|
52
|
+
|
53
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
54
|
+
|
55
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
56
|
+
|
57
|
+
## Contributing
|
58
|
+
|
59
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/Shopify/grpc_fork_safety.
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "version"
|
4
|
+
|
5
|
+
if defined? GRPC::Core # ::GRPC may be loaded by bundler from `grpc.gemspec` so we check `GRPC::Core`
|
6
|
+
raise <<~ERROR
|
7
|
+
GRPC was loaded before `grpc_fork_safety` preventing to enable fork support
|
8
|
+
|
9
|
+
You may need to set `require: false` in your Gemfile where `grpc` is listed or
|
10
|
+
move `gem "grpc_fork_safety"` before `gem "grpc"`in your Gemfile.
|
11
|
+
ERROR
|
12
|
+
end
|
13
|
+
|
14
|
+
ENV["GRPC_ENABLE_FORK_SUPPORT"] = "1"
|
15
|
+
require "grpc"
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "grpc_fork_safety/init"
|
4
|
+
|
5
|
+
module GrpcForkSafety
|
6
|
+
Error = Class.new(StandardError)
|
7
|
+
|
8
|
+
class LifeCycle
|
9
|
+
def initialize(grpc = ::GRPC, process = ::Process)
|
10
|
+
@grpc = grpc
|
11
|
+
@process = process
|
12
|
+
@shutdown_by = nil
|
13
|
+
@keep_disabled = false
|
14
|
+
@before_disable = []
|
15
|
+
@after_enable = []
|
16
|
+
end
|
17
|
+
|
18
|
+
def before_disable(&block)
|
19
|
+
raise Error, "No block given" unless block_given?
|
20
|
+
|
21
|
+
@before_disable << block
|
22
|
+
end
|
23
|
+
|
24
|
+
def after_enable(&block)
|
25
|
+
raise Error, "No block given" unless block_given?
|
26
|
+
|
27
|
+
@after_enable << block
|
28
|
+
end
|
29
|
+
|
30
|
+
def keep_disabled!
|
31
|
+
return if @keep_disabled
|
32
|
+
|
33
|
+
@keep_disabled = true
|
34
|
+
before_fork
|
35
|
+
end
|
36
|
+
|
37
|
+
def keep_disabled?
|
38
|
+
@keep_disabled
|
39
|
+
end
|
40
|
+
|
41
|
+
def reenable!
|
42
|
+
return unless @keep_disabled
|
43
|
+
|
44
|
+
@keep_disabled = false
|
45
|
+
after_fork
|
46
|
+
end
|
47
|
+
|
48
|
+
def before_fork
|
49
|
+
return if @shutdown_by
|
50
|
+
|
51
|
+
@before_disable.each(&:call)
|
52
|
+
|
53
|
+
@grpc.prefork
|
54
|
+
@shutdown_by = @process.pid
|
55
|
+
end
|
56
|
+
|
57
|
+
def after_fork
|
58
|
+
if @shutdown_by.nil?
|
59
|
+
# noop
|
60
|
+
elsif @shutdown_by == @process.pid # In parent
|
61
|
+
unless @keep_disabled
|
62
|
+
@grpc.postfork_parent
|
63
|
+
@shutdown_by = nil
|
64
|
+
|
65
|
+
@after_enable.each do |cb|
|
66
|
+
cb.call(false)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
else
|
70
|
+
@keep_disabled = false
|
71
|
+
@shutdown_by = nil
|
72
|
+
@grpc.postfork_child
|
73
|
+
@after_enable.each do |cb|
|
74
|
+
cb.call(true)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class NoopLifeCycle
|
81
|
+
def initialize
|
82
|
+
@keep_disabled = false
|
83
|
+
end
|
84
|
+
|
85
|
+
def keep_disabled!
|
86
|
+
@keep_disabled = true
|
87
|
+
end
|
88
|
+
|
89
|
+
def keep_disabled?
|
90
|
+
@keep_disabled
|
91
|
+
end
|
92
|
+
|
93
|
+
def reenable!
|
94
|
+
@keep_disabled = false
|
95
|
+
end
|
96
|
+
|
97
|
+
def before_fork; end
|
98
|
+
|
99
|
+
def after_fork; end
|
100
|
+
|
101
|
+
def before_disable; end
|
102
|
+
|
103
|
+
def after_enable; end
|
104
|
+
end
|
105
|
+
|
106
|
+
GRPC_FORK_SUPPORT = RUBY_PLATFORM.match?(/linux/i)
|
107
|
+
|
108
|
+
@lifecycle = if GRPC_FORK_SUPPORT
|
109
|
+
LifeCycle.new
|
110
|
+
else
|
111
|
+
NoopLifeCycle.new
|
112
|
+
end
|
113
|
+
|
114
|
+
class << self
|
115
|
+
def keep_disabled!
|
116
|
+
@lifecycle.keep_disabled!
|
117
|
+
end
|
118
|
+
|
119
|
+
def reenable!
|
120
|
+
@lifecycle.keep_disabled = false
|
121
|
+
@lifecycle.after_fork
|
122
|
+
end
|
123
|
+
|
124
|
+
def before_disable(&)
|
125
|
+
@lifecycle.before_disable(&)
|
126
|
+
end
|
127
|
+
|
128
|
+
def after_enable(&)
|
129
|
+
@lifecycle.after_enable(&)
|
130
|
+
end
|
131
|
+
|
132
|
+
def _before_fork_hook
|
133
|
+
@lifecycle.before_fork
|
134
|
+
end
|
135
|
+
|
136
|
+
def _after_fork_hook
|
137
|
+
@lifecycle.after_fork
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "grpc_fork_safety/no_patch"
|
4
|
+
|
5
|
+
module GrpcForkSafety
|
6
|
+
module ProcessExtension
|
7
|
+
def _fork
|
8
|
+
GrpcForkSafety._before_fork_hook
|
9
|
+
pid = super
|
10
|
+
GrpcForkSafety._after_fork_hook
|
11
|
+
pid
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def patch!
|
17
|
+
::Process.singleton_class.prepend(ProcessExtension)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: grpc_fork_safety
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jean Boussier
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-07-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: grpc
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.57.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.57.0
|
27
|
+
description:
|
28
|
+
email:
|
29
|
+
- jean.boussier@gmail.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- ".rubocop.yml"
|
35
|
+
- ".ruby-version"
|
36
|
+
- CHANGELOG.md
|
37
|
+
- README.md
|
38
|
+
- Rakefile
|
39
|
+
- lib/grpc_fork_safety.rb
|
40
|
+
- lib/grpc_fork_safety/init.rb
|
41
|
+
- lib/grpc_fork_safety/no_patch.rb
|
42
|
+
- lib/grpc_fork_safety/patch.rb
|
43
|
+
- lib/grpc_fork_safety/version.rb
|
44
|
+
homepage: https://github.com/Shopify/grpc_fork_safety
|
45
|
+
licenses: []
|
46
|
+
metadata:
|
47
|
+
allowed_push_host: https://rubygems.org
|
48
|
+
homepage_uri: https://github.com/Shopify/grpc_fork_safety
|
49
|
+
source_code_uri: https://github.com/Shopify/grpc_fork_safety
|
50
|
+
changelog_uri: https://github.com/Shopify/grpc_fork_safety/blob/main/CHANGELOG.md
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: 3.1.0
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
requirements: []
|
66
|
+
rubygems_version: 3.5.11
|
67
|
+
signing_key:
|
68
|
+
specification_version: 4
|
69
|
+
summary: Simple gems to facilitate making the grpc gem fork safe
|
70
|
+
test_files: []
|