process_bot 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +180 -4
- data/Gemfile +5 -4
- data/Gemfile.lock +75 -0
- data/exe/process_bot +36 -0
- data/lib/process_bot/capistrano/puma/common.rb +86 -0
- data/lib/process_bot/capistrano/puma.rake +9 -6
- data/lib/process_bot/capistrano/puma.rb +4 -6
- data/lib/process_bot/capistrano/sidekiq.rake +6 -9
- data/lib/process_bot/capistrano/sidekiq.rb +5 -3
- data/lib/process_bot/capistrano/sidekiq_helpers.rb +33 -36
- data/lib/process_bot/capistrano.rb +4 -0
- data/lib/process_bot/control_socket.rb +39 -0
- data/lib/process_bot/logger.rb +22 -0
- data/lib/process_bot/options.rb +21 -0
- data/lib/process_bot/process/handlers/sidekiq.rb +55 -0
- data/lib/process_bot/process/handlers.rb +3 -0
- data/lib/process_bot/process/runner.rb +55 -0
- data/lib/process_bot/process.rb +49 -2
- data/lib/process_bot/version.rb +1 -3
- data/lib/process_bot.rb +6 -3
- data/peak_flow.yml +4 -0
- data/process_bot.gemspec +45 -0
- metadata +75 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 918adb2b2275f38d3b22eb926a5da3b021f667d4a7290a3b0b1d9ea7bb56a2c2
|
4
|
+
data.tar.gz: 03c557694d0a91f78f25dc4689f2b99c46b626ebeed5816f8e2e0346e29dd482
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2053d076158df45b723855cee991d47852efb18b34ace65e24005798c7d9d1f1ffff126d1fc7409ba3554e4bfa3bf9855c13dfec5bcfa14ac79aac57d9409acf
|
7
|
+
data.tar.gz: 5622bc3069e029485876c7329bd0658b3bf7b3c4b265a40e51421bab04e0b898367f91c864dbe7caf1de93b317e9ba1fcd4787971fd4dc9e28528bf4f14a8df8
|
data/.rubocop.yml
CHANGED
@@ -1,13 +1,189 @@
|
|
1
1
|
AllCops:
|
2
|
+
DisplayCopNames: true
|
3
|
+
DisplayStyleGuide: true
|
4
|
+
NewCops: enable
|
2
5
|
TargetRubyVersion: 2.6
|
3
6
|
|
4
|
-
|
7
|
+
require:
|
8
|
+
- rubocop-performance
|
9
|
+
- rubocop-rake
|
10
|
+
- rubocop-rspec
|
11
|
+
|
12
|
+
Layout/AccessModifierIndentation:
|
13
|
+
EnforcedStyle: outdent
|
14
|
+
|
15
|
+
Layout/ArgumentAlignment:
|
16
|
+
EnforcedStyle: with_fixed_indentation
|
17
|
+
|
18
|
+
Layout/CaseIndentation:
|
19
|
+
EnforcedStyle: end
|
20
|
+
|
21
|
+
Layout/EmptyLines:
|
22
|
+
Enabled: false
|
23
|
+
|
24
|
+
Layout/EmptyLinesAroundArguments:
|
25
|
+
Enabled: false
|
26
|
+
|
27
|
+
Layout/EndAlignment:
|
28
|
+
EnforcedStyleAlignWith: variable
|
29
|
+
|
30
|
+
Layout/LineEndStringConcatenationIndentation:
|
31
|
+
EnforcedStyle: indented
|
32
|
+
|
33
|
+
Layout/LineLength:
|
34
|
+
Max: 160
|
35
|
+
|
36
|
+
Layout/MultilineMethodCallIndentation:
|
37
|
+
EnforcedStyle: indented
|
38
|
+
|
39
|
+
Layout/MultilineOperationIndentation:
|
40
|
+
EnforcedStyle: indented
|
41
|
+
|
42
|
+
Layout/ParameterAlignment:
|
43
|
+
EnforcedStyle: with_fixed_indentation
|
44
|
+
|
45
|
+
Layout/RescueEnsureAlignment:
|
46
|
+
Enabled: false
|
47
|
+
|
48
|
+
Layout/SpaceAroundMethodCallOperator:
|
49
|
+
Enabled: true
|
50
|
+
|
51
|
+
Layout/SpaceInsideHashLiteralBraces:
|
52
|
+
EnforcedStyle: no_space
|
53
|
+
|
54
|
+
Lint/MissingSuper:
|
55
|
+
Enabled: false
|
56
|
+
|
57
|
+
Lint/RaiseException:
|
58
|
+
Enabled: true
|
59
|
+
|
60
|
+
Lint/StructNewOverride:
|
61
|
+
Enabled: true
|
62
|
+
|
63
|
+
# Metrics/AbcSize:
|
64
|
+
# Max: 25
|
65
|
+
|
66
|
+
Metrics/BlockLength:
|
67
|
+
Enabled: false
|
68
|
+
|
69
|
+
Metrics/ClassLength:
|
70
|
+
Max: 250
|
71
|
+
|
72
|
+
Metrics/CyclomaticComplexity:
|
73
|
+
Max: 12
|
74
|
+
|
75
|
+
Metrics/MethodLength:
|
76
|
+
Max: 50
|
77
|
+
|
78
|
+
Metrics/ParameterLists:
|
79
|
+
CountKeywordArgs: false
|
80
|
+
|
81
|
+
Metrics/PerceivedComplexity:
|
82
|
+
Max: 12
|
83
|
+
|
84
|
+
RSpec/AnyInstance:
|
85
|
+
Enabled: false
|
86
|
+
|
87
|
+
Style/CaseLikeIf:
|
88
|
+
Enabled: false
|
89
|
+
|
90
|
+
RSpec/ContextWording:
|
91
|
+
Enabled: false
|
92
|
+
|
93
|
+
RSpec/DescribeClass:
|
94
|
+
Enabled: false
|
95
|
+
|
96
|
+
RSpec/DescribedClass:
|
97
|
+
Enabled: false
|
98
|
+
|
99
|
+
RSpec/ExampleLength:
|
100
|
+
Enabled: false
|
101
|
+
|
102
|
+
RSpec/LetSetup:
|
103
|
+
Enabled: false
|
104
|
+
|
105
|
+
RSpec/MessageSpies:
|
106
|
+
Enabled: false
|
107
|
+
|
108
|
+
RSpec/MultipleExpectations:
|
109
|
+
Enabled: false
|
110
|
+
|
111
|
+
RSpec/MultipleMemoizedHelpers:
|
112
|
+
Enabled: false
|
113
|
+
|
114
|
+
RSpec/NamedSubject:
|
115
|
+
Enabled: false
|
116
|
+
|
117
|
+
RSpec/NestedGroups:
|
118
|
+
Enabled: false
|
119
|
+
|
120
|
+
RSpec/StubbedMock:
|
121
|
+
Enabled: false
|
122
|
+
|
123
|
+
Style/ClassAndModuleChildren:
|
124
|
+
EnforcedStyle: compact
|
125
|
+
|
126
|
+
Style/ConditionalAssignment:
|
127
|
+
Enabled: false
|
128
|
+
|
129
|
+
Style/Documentation:
|
130
|
+
Enabled: false
|
131
|
+
|
132
|
+
Style/ExponentialNotation:
|
133
|
+
Enabled: true
|
134
|
+
|
135
|
+
Style/FrozenStringLiteralComment:
|
136
|
+
Enabled: false
|
137
|
+
|
138
|
+
Style/HashAsLastArrayItem:
|
139
|
+
Enabled: false
|
140
|
+
|
141
|
+
Style/HashEachMethods:
|
142
|
+
Enabled: true
|
143
|
+
|
144
|
+
Style/HashTransformKeys:
|
145
|
+
Enabled: true
|
146
|
+
|
147
|
+
Style/HashTransformValues:
|
5
148
|
Enabled: true
|
149
|
+
|
150
|
+
# Will report offences for many places that are much more readable without using a guard clause
|
151
|
+
Style/GuardClause:
|
152
|
+
Enabled: false
|
153
|
+
|
154
|
+
Style/KeywordParametersOrder:
|
155
|
+
Enabled: false
|
156
|
+
|
157
|
+
Style/Lambda:
|
158
|
+
Enabled: false
|
159
|
+
|
160
|
+
Style/LambdaCall:
|
161
|
+
Enabled: false
|
162
|
+
|
163
|
+
Style/MultipleComparison:
|
164
|
+
Enabled: false
|
165
|
+
|
166
|
+
Style/RegexpLiteral:
|
167
|
+
Enabled: false
|
168
|
+
|
169
|
+
Style/StringLiterals:
|
6
170
|
EnforcedStyle: double_quotes
|
7
171
|
|
8
172
|
Style/StringLiteralsInInterpolation:
|
173
|
+
Enabled: false
|
174
|
+
|
175
|
+
Style/NilComparison:
|
176
|
+
Enabled: false
|
177
|
+
|
178
|
+
Style/SignalException:
|
179
|
+
EnforcedStyle: only_raise
|
180
|
+
|
181
|
+
Style/SymbolArray:
|
182
|
+
Enabled: false
|
183
|
+
|
184
|
+
Style/TrivialAccessors:
|
185
|
+
ExactNameMatch: true
|
9
186
|
Enabled: true
|
10
|
-
EnforcedStyle: double_quotes
|
11
187
|
|
12
|
-
|
13
|
-
|
188
|
+
Style/WordArray:
|
189
|
+
Enabled: false
|
data/Gemfile
CHANGED
@@ -5,8 +5,9 @@ source "https://rubygems.org"
|
|
5
5
|
# Specify your gem's dependencies in process_bot.gemspec
|
6
6
|
gemspec
|
7
7
|
|
8
|
-
gem "rake"
|
8
|
+
gem "rake"
|
9
|
+
gem "rspec"
|
10
|
+
gem "rubocop"
|
11
|
+
gem "string-cases"
|
9
12
|
|
10
|
-
gem "
|
11
|
-
|
12
|
-
gem "rubocop", "~> 1.21"
|
13
|
+
gem "pry"
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
process_bot (0.1.2)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
ast (2.4.2)
|
10
|
+
coderay (1.1.3)
|
11
|
+
diff-lcs (1.5.0)
|
12
|
+
json (2.6.2)
|
13
|
+
method_source (1.0.0)
|
14
|
+
parallel (1.22.1)
|
15
|
+
parser (3.1.2.1)
|
16
|
+
ast (~> 2.4.1)
|
17
|
+
pry (0.14.1)
|
18
|
+
coderay (~> 1.1)
|
19
|
+
method_source (~> 1.0)
|
20
|
+
rainbow (3.1.1)
|
21
|
+
rake (13.0.6)
|
22
|
+
regexp_parser (2.6.0)
|
23
|
+
rexml (3.2.5)
|
24
|
+
rspec (3.11.0)
|
25
|
+
rspec-core (~> 3.11.0)
|
26
|
+
rspec-expectations (~> 3.11.0)
|
27
|
+
rspec-mocks (~> 3.11.0)
|
28
|
+
rspec-core (3.11.0)
|
29
|
+
rspec-support (~> 3.11.0)
|
30
|
+
rspec-expectations (3.11.0)
|
31
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
32
|
+
rspec-support (~> 3.11.0)
|
33
|
+
rspec-mocks (3.11.1)
|
34
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
35
|
+
rspec-support (~> 3.11.0)
|
36
|
+
rspec-support (3.11.0)
|
37
|
+
rubocop (1.36.0)
|
38
|
+
json (~> 2.3)
|
39
|
+
parallel (~> 1.10)
|
40
|
+
parser (>= 3.1.2.1)
|
41
|
+
rainbow (>= 2.2.2, < 4.0)
|
42
|
+
regexp_parser (>= 1.8, < 3.0)
|
43
|
+
rexml (>= 3.2.5, < 4.0)
|
44
|
+
rubocop-ast (>= 1.20.1, < 2.0)
|
45
|
+
ruby-progressbar (~> 1.7)
|
46
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
47
|
+
rubocop-ast (1.21.0)
|
48
|
+
parser (>= 3.1.1.0)
|
49
|
+
rubocop-performance (1.15.0)
|
50
|
+
rubocop (>= 1.7.0, < 2.0)
|
51
|
+
rubocop-ast (>= 0.4.0)
|
52
|
+
rubocop-rake (0.6.0)
|
53
|
+
rubocop (~> 1.0)
|
54
|
+
rubocop-rspec (2.11.1)
|
55
|
+
rubocop (~> 1.19)
|
56
|
+
ruby-progressbar (1.11.0)
|
57
|
+
string-cases (0.0.4)
|
58
|
+
unicode-display_width (2.3.0)
|
59
|
+
|
60
|
+
PLATFORMS
|
61
|
+
x86_64-linux
|
62
|
+
|
63
|
+
DEPENDENCIES
|
64
|
+
process_bot!
|
65
|
+
pry
|
66
|
+
rake
|
67
|
+
rspec
|
68
|
+
rubocop
|
69
|
+
rubocop-performance
|
70
|
+
rubocop-rake
|
71
|
+
rubocop-rspec
|
72
|
+
string-cases
|
73
|
+
|
74
|
+
BUNDLED WITH
|
75
|
+
2.3.8
|
data/exe/process_bot
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "pathname"
|
4
|
+
|
5
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
6
|
+
Pathname.new(__FILE__).realpath)
|
7
|
+
|
8
|
+
require "bundler/setup"
|
9
|
+
require "optparse"
|
10
|
+
require "string-cases"
|
11
|
+
require_relative "../lib/process_bot"
|
12
|
+
|
13
|
+
options = ProcessBot::Options.new
|
14
|
+
argv_i = 0
|
15
|
+
|
16
|
+
while argv_i < ARGV.length
|
17
|
+
arg = ARGV.fetch(argv_i)
|
18
|
+
|
19
|
+
if (match = arg.match(/\A--(.+)\Z/))
|
20
|
+
key = match[1].tr("-", "_").to_sym
|
21
|
+
argv_i += 1
|
22
|
+
value = ARGV.fetch(argv_i)
|
23
|
+
|
24
|
+
options.set(key, value)
|
25
|
+
else
|
26
|
+
raise "Unknown option: #{arg}"
|
27
|
+
end
|
28
|
+
|
29
|
+
argv_i += 1
|
30
|
+
end
|
31
|
+
|
32
|
+
pp options.options
|
33
|
+
|
34
|
+
ProcessBot::Process
|
35
|
+
.new(options)
|
36
|
+
.execute!
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module ProcessBot::Capistrano::Puma::Common
|
2
|
+
def puma_switch_user(role)
|
3
|
+
user = puma_user(role)
|
4
|
+
if user == role.user
|
5
|
+
yield
|
6
|
+
else
|
7
|
+
backend.as user, &block
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def puma_user(role)
|
12
|
+
properties = role.properties
|
13
|
+
properties.fetch(:puma_user) || # local property for puma only
|
14
|
+
fetch(:puma_user) ||
|
15
|
+
properties.fetch(:run_as) || # global property across multiple capistrano gems
|
16
|
+
role.user
|
17
|
+
end
|
18
|
+
|
19
|
+
def puma_bind
|
20
|
+
Array(fetch(:puma_bind)).collect do |bind|
|
21
|
+
"bind '#{bind}'"
|
22
|
+
end.join("\n")
|
23
|
+
end
|
24
|
+
|
25
|
+
def compiled_template_puma(from, role)
|
26
|
+
@role = role
|
27
|
+
file = [
|
28
|
+
"lib/capistrano/templates/#{from}-#{role.hostname}-#{fetch(:stage)}.rb",
|
29
|
+
"lib/capistrano/templates/#{from}-#{role.hostname}.rb",
|
30
|
+
"lib/capistrano/templates/#{from}-#{fetch(:stage)}.rb",
|
31
|
+
"lib/capistrano/templates/#{from}.rb.erb",
|
32
|
+
"lib/capistrano/templates/#{from}.rb",
|
33
|
+
"lib/capistrano/templates/#{from}.erb",
|
34
|
+
"config/deploy/templates/#{from}.rb.erb",
|
35
|
+
"config/deploy/templates/#{from}.rb",
|
36
|
+
"config/deploy/templates/#{from}.erb",
|
37
|
+
File.expand_path("../templates/#{from}.erb", __FILE__),
|
38
|
+
File.expand_path("../templates/#{from}.rb.erb", __FILE__)
|
39
|
+
].detect { |path| File.file?(path) }
|
40
|
+
erb = File.read(file)
|
41
|
+
StringIO.new(ERB.new(erb, trim_mode: "-").result(binding))
|
42
|
+
end
|
43
|
+
|
44
|
+
def template_puma(from, to, role)
|
45
|
+
backend.upload! compiled_template_puma(from, role), to
|
46
|
+
end
|
47
|
+
|
48
|
+
PumaBind = Struct.new(:full_address, :kind, :address) do
|
49
|
+
def unix?
|
50
|
+
kind == :unix
|
51
|
+
end
|
52
|
+
|
53
|
+
def ssl?
|
54
|
+
kind == :ssl
|
55
|
+
end
|
56
|
+
|
57
|
+
def tcp
|
58
|
+
kind == :tcp || ssl?
|
59
|
+
end
|
60
|
+
|
61
|
+
def local
|
62
|
+
if unix?
|
63
|
+
self
|
64
|
+
else
|
65
|
+
PumaBind.new(
|
66
|
+
localize_address(full_address),
|
67
|
+
kind,
|
68
|
+
localize_address(address)
|
69
|
+
)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def localize_address(address)
|
76
|
+
address.gsub(/0\.0\.0\.0(.+)/, "127.0.0.1\\1")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def puma_binds
|
81
|
+
Array(fetch(:puma_bind)).map do |m|
|
82
|
+
etype, address = /(tcp|unix|ssl):\/{1,2}(.+)/.match(m).captures
|
83
|
+
PumaBind.new(m, etype.to_sym, address)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -6,7 +6,7 @@ namespace :process_bot do
|
|
6
6
|
task :start do
|
7
7
|
on roles(fetch(:puma_role)) do |role|
|
8
8
|
git_plugin.puma_switch_user(role) do
|
9
|
-
if test
|
9
|
+
if test("[ -f #{fetch(:puma_pid)} ]") && test(:kill, "-0 $( cat #{fetch(:puma_pid)} )")
|
10
10
|
info "Puma is already running"
|
11
11
|
else
|
12
12
|
within current_path do
|
@@ -24,7 +24,9 @@ namespace :process_bot do
|
|
24
24
|
"--control-token foobar"
|
25
25
|
]
|
26
26
|
|
27
|
-
command = "/usr/bin/screen -dmS puma-#{latest_release_version}
|
27
|
+
command = "/usr/bin/screen -dmS puma-#{latest_release_version} " \
|
28
|
+
"bash -c 'cd #{release_path} && #{SSHKit.config.command_map.prefix[:puma].join(" ")} puma #{puma_args.join(" ")}'"
|
29
|
+
|
28
30
|
execute command
|
29
31
|
end
|
30
32
|
end
|
@@ -36,7 +38,7 @@ namespace :process_bot do
|
|
36
38
|
%w[halt stop status].map do |command|
|
37
39
|
desc "#{command} puma"
|
38
40
|
task command do
|
39
|
-
on roles
|
41
|
+
on roles(fetch(:puma_role)) do |role|
|
40
42
|
within current_path do
|
41
43
|
git_plugin.puma_switch_user(role) do
|
42
44
|
with rack_env: fetch(:puma_env) do
|
@@ -48,7 +50,7 @@ namespace :process_bot do
|
|
48
50
|
execute :rm, fetch(:puma_pid)
|
49
51
|
end
|
50
52
|
else
|
51
|
-
#pid file not found, so puma is probably not running or it using another pidfile
|
53
|
+
# pid file not found, so puma is probably not running or it using another pidfile
|
52
54
|
warn "Puma not running"
|
53
55
|
end
|
54
56
|
end
|
@@ -61,12 +63,12 @@ namespace :process_bot do
|
|
61
63
|
%w[phased-restart restart].map do |command|
|
62
64
|
desc "#{command} puma"
|
63
65
|
task command do
|
64
|
-
on roles
|
66
|
+
on roles(fetch(:puma_role)) do |role|
|
65
67
|
within current_path do
|
66
68
|
git_plugin.puma_switch_user(role) do
|
67
69
|
with rack_env: fetch(:puma_env) do
|
68
70
|
if git_plugin.puma_running?
|
69
|
-
# NOTE pid exist but state file is nonsense, so ignore that case
|
71
|
+
# NOTE: pid exist but state file is nonsense, so ignore that case
|
70
72
|
git_plugin.run_puma_command(command)
|
71
73
|
else
|
72
74
|
# Puma is not running or state file is not present : Run it
|
@@ -79,6 +81,7 @@ namespace :process_bot do
|
|
79
81
|
end
|
80
82
|
end
|
81
83
|
|
84
|
+
desc "Restarts Puma phased if using workers and preload and otherwise a normal restart."
|
82
85
|
task :smart_restart do
|
83
86
|
if !fetch(:puma_preload_app) && fetch(:puma_workers, 0).to_i > 1
|
84
87
|
invoke "process_bot:puma:phased-restart"
|
@@ -1,12 +1,10 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
class ProcessBot::Capistrano::Puma < Capistrano::Plugin
|
2
|
+
autoload :Common, "#{__dir__}/puma/common"
|
3
3
|
|
4
|
-
|
5
|
-
after 'deploy:finished', 'process_bot:puma:smart_restart'
|
6
|
-
end
|
4
|
+
include ::ProcessBot::Capistrano::Puma::Common
|
7
5
|
|
8
6
|
def define_tasks
|
9
|
-
eval_rakefile File.expand_path(
|
7
|
+
eval_rakefile File.expand_path("./puma.rake", __dir__)
|
10
8
|
end
|
11
9
|
|
12
10
|
def puma_running?
|
@@ -1,6 +1,7 @@
|
|
1
1
|
git_plugin = self
|
2
2
|
|
3
3
|
namespace :load do
|
4
|
+
desc "Default variables for Sidekiq"
|
4
5
|
task :defaults do
|
5
6
|
set :sidekiq_default_hooks, true
|
6
7
|
|
@@ -18,17 +19,12 @@ namespace :load do
|
|
18
19
|
set :chruby_map_bins, fetch(:chruby_map_bins).to_a.concat(%w[sidekiq sidekiqctl])
|
19
20
|
# Bundler integration
|
20
21
|
set :bundle_bins, fetch(:bundle_bins).to_a.concat(%w[sidekiq sidekiqctl])
|
21
|
-
# Init system integration
|
22
|
-
set :init_system, -> { nil }
|
23
|
-
# systemd integration
|
24
|
-
set :service_unit_name, "sidekiq-#{fetch(:stage)}.service"
|
25
|
-
set :upstart_service_name, "sidekiq"
|
26
22
|
end
|
27
23
|
end
|
28
24
|
|
29
25
|
namespace :process_bot do
|
30
26
|
namespace :sidekiq do
|
31
|
-
desc
|
27
|
+
desc "Quiet sidekiq (stop fetching new tasks from Redis)"
|
32
28
|
task :quiet do
|
33
29
|
on roles fetch(:sidekiq_roles) do |role|
|
34
30
|
git_plugin.switch_user(role) do
|
@@ -39,7 +35,7 @@ namespace :process_bot do
|
|
39
35
|
end
|
40
36
|
end
|
41
37
|
|
42
|
-
desc
|
38
|
+
desc "Stop Sidekiq (graceful shutdown within timeout, put unfinished tasks back to Redis)"
|
43
39
|
task :stop do
|
44
40
|
on roles fetch(:sidekiq_roles) do |role|
|
45
41
|
git_plugin.switch_user(role) do
|
@@ -50,6 +46,7 @@ namespace :process_bot do
|
|
50
46
|
end
|
51
47
|
end
|
52
48
|
|
49
|
+
desc "Stops Sidekiq after a set amount of time"
|
53
50
|
task :stop_after_time do
|
54
51
|
on roles fetch(:sidekiq_roles) do |role|
|
55
52
|
git_plugin.switch_user(role) do
|
@@ -60,7 +57,7 @@ namespace :process_bot do
|
|
60
57
|
end
|
61
58
|
end
|
62
59
|
|
63
|
-
desc
|
60
|
+
desc "Start sidekiq"
|
64
61
|
task :start do
|
65
62
|
on roles fetch(:sidekiq_roles) do |role|
|
66
63
|
git_plugin.switch_user(role) do
|
@@ -72,7 +69,7 @@ namespace :process_bot do
|
|
72
69
|
end
|
73
70
|
end
|
74
71
|
|
75
|
-
desc
|
72
|
+
desc "Restart sidekiq"
|
76
73
|
task :restart do
|
77
74
|
invoke! "process_bot:sidekiq:stop"
|
78
75
|
invoke! "process_bot:sidekiq:start"
|
@@ -1,7 +1,9 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require_relative "sidekiq_helpers"
|
2
|
+
|
3
|
+
class ProcessBot::Capistrano::Sidekiq < Capistrano::Plugin
|
4
|
+
include ProcessBot::Capistrano::SidekiqHelpers
|
3
5
|
|
4
6
|
def define_tasks
|
5
|
-
eval_rakefile File.expand_path("./sidekiq.rake",
|
7
|
+
eval_rakefile File.expand_path("./sidekiq.rake", __dir__)
|
6
8
|
end
|
7
9
|
end
|
@@ -1,44 +1,36 @@
|
|
1
|
-
module ProcessBot::
|
1
|
+
module ProcessBot::Capistrano::SidekiqHelpers
|
2
2
|
def sidekiq_require
|
3
|
-
if fetch(:sidekiq_require)
|
4
|
-
"--require #{fetch(:sidekiq_require)}"
|
5
|
-
end
|
3
|
+
"--require #{fetch(:sidekiq_require)}" if fetch(:sidekiq_require)
|
6
4
|
end
|
7
5
|
|
8
6
|
def sidekiq_config
|
9
|
-
if fetch(:sidekiq_config)
|
10
|
-
"--config #{fetch(:sidekiq_config)}"
|
11
|
-
end
|
7
|
+
"--config #{fetch(:sidekiq_config)}" if fetch(:sidekiq_config)
|
12
8
|
end
|
13
9
|
|
14
10
|
def sidekiq_concurrency
|
15
|
-
if fetch(:sidekiq_concurrency)
|
16
|
-
"--concurrency #{fetch(:sidekiq_concurrency)}"
|
17
|
-
end
|
11
|
+
"--concurrency #{fetch(:sidekiq_concurrency)}" if fetch(:sidekiq_concurrency)
|
18
12
|
end
|
19
13
|
|
20
14
|
def sidekiq_queues
|
21
15
|
Array(fetch(:sidekiq_queue)).map do |queue|
|
22
16
|
"--queue #{queue}"
|
23
|
-
end.join(
|
17
|
+
end.join(" ")
|
24
18
|
end
|
25
19
|
|
26
20
|
def sidekiq_logfile
|
27
21
|
fetch(:sidekiq_log)
|
28
22
|
end
|
29
23
|
|
30
|
-
def switch_user(role)
|
24
|
+
def switch_user(role, &block)
|
31
25
|
su_user = sidekiq_user(role)
|
32
26
|
if su_user == role.user
|
33
27
|
yield
|
34
28
|
else
|
35
|
-
as su_user
|
36
|
-
yield
|
37
|
-
end
|
29
|
+
as su_user, &block
|
38
30
|
end
|
39
31
|
end
|
40
32
|
|
41
|
-
VALID_SIGNALS = ["TERM", "TSTP"]
|
33
|
+
VALID_SIGNALS = ["TERM", "TSTP"].freeze
|
42
34
|
def stop_sidekiq(pid:, signal:)
|
43
35
|
raise "Invalid PID: #{pid}" unless pid.to_s.match?(/\A\d+\Z/)
|
44
36
|
raise "Invalid signal: #{signal}" unless VALID_SIGNALS.include?(signal)
|
@@ -53,7 +45,7 @@ module ProcessBot::Sidekiq::Helpers
|
|
53
45
|
time = ENV["STOP_AFTER_TIME"] || fetch(:sidekiq_stop_after_time)
|
54
46
|
raise "Invalid time: #{time}" unless time.to_s.match?(/\A\d+\Z/)
|
55
47
|
|
56
|
-
backend.execute "screen -dmS stopsidekiq#{pid} sleep #{time}
|
48
|
+
backend.execute "screen -dmS stopsidekiq#{pid} bash -c \"sleep #{time} && kill -#{signal} #{pid}\""
|
57
49
|
end
|
58
50
|
|
59
51
|
def running_sidekiq_processes
|
@@ -94,23 +86,7 @@ module ProcessBot::Sidekiq::Helpers
|
|
94
86
|
backend.capture(:echo, SSHKit.config.command_map[:bundle]).strip
|
95
87
|
end
|
96
88
|
|
97
|
-
def start_sidekiq(idx = 0)
|
98
|
-
args = []
|
99
|
-
args.push "--environment #{fetch(:sidekiq_env)}"
|
100
|
-
#args.push "--logfile #{fetch(:sidekiq_log)}" if fetch(:sidekiq_log)
|
101
|
-
args.push "--require #{fetch(:sidekiq_require)}" if fetch(:sidekiq_require)
|
102
|
-
args.push "--tag #{fetch(:sidekiq_tag)}" if fetch(:sidekiq_tag)
|
103
|
-
Array(fetch(:sidekiq_queue)).each do |queue|
|
104
|
-
args.push "--queue #{queue}"
|
105
|
-
end
|
106
|
-
args.push "--config #{fetch(:sidekiq_config)}" if fetch(:sidekiq_config)
|
107
|
-
args.push "--concurrency #{fetch(:sidekiq_concurrency)}" if fetch(:sidekiq_concurrency)
|
108
|
-
if (process_options = fetch(:sidekiq_options_per_process))
|
109
|
-
args.push process_options[idx]
|
110
|
-
end
|
111
|
-
# use sidekiq_options for special options
|
112
|
-
args.push fetch(:sidekiq_options) if fetch(:sidekiq_options)
|
113
|
-
|
89
|
+
def start_sidekiq(idx = 0) # rubocop:disable Metrics/AbcSize
|
114
90
|
releases = backend.capture(:ls, "-x", releases_path).split
|
115
91
|
releases << release_timestamp.to_s if release_timestamp
|
116
92
|
releases.uniq
|
@@ -118,13 +94,34 @@ module ProcessBot::Sidekiq::Helpers
|
|
118
94
|
latest_release_version = releases.last
|
119
95
|
raise "Invalid release timestamp: #{release_timestamp}" unless latest_release_version
|
120
96
|
|
97
|
+
args = [
|
98
|
+
"--id", "sidekiq-#{latest_release_version}-#{idx}",
|
99
|
+
"--handler", "sidekiq",
|
100
|
+
"--bundle-prefix", SSHKit.config.command_map.prefix[:bundle].join(" "),
|
101
|
+
"--sidekiq-environment", fetch(:sidekiq_env),
|
102
|
+
"--port", 7050 + idx
|
103
|
+
]
|
104
|
+
args += ["--log-file-path", fetch(:sidekiq_log)] if fetch(:sidekiq_log)
|
105
|
+
args += ["--sidekiq-require", fetch(:sidekiq_require)] if fetch(:sidekiq_require)
|
106
|
+
args += ["--sidekiq-tag", fetch(:sidekiq_tag)] if fetch(:sidekiq_tag)
|
107
|
+
args += ["--sidekiq-queues", Array(fetch(:sidekiq_queue)).join(",")] if fetch(:sidekiq_queue)
|
108
|
+
args += ["--sidekiq-config", fetch(:sidekiq_config)] if fetch(:sidekiq_config)
|
109
|
+
args += ["--sidekiq-concurrency", fetch(:sidekiq_concurrency)] if fetch(:sidekiq_concurrency)
|
110
|
+
if (process_options = fetch(:sidekiq_options_per_process))
|
111
|
+
args += process_options[idx]
|
112
|
+
end
|
113
|
+
args += fetch(:sidekiq_options) if fetch(:sidekiq_options)
|
114
|
+
|
121
115
|
screen_args = ["-dmS sidekiq-#{idx}-#{latest_release_version}"]
|
122
116
|
screen_args << "-L -Logfile #{fetch(:sidekiq_log)}" if fetch(:sidekiq_log)
|
123
117
|
|
124
|
-
|
125
|
-
|
118
|
+
process_bot_args = args.compact.map { |arg| "\"#{arg}\"" }
|
119
|
+
|
120
|
+
command = "/usr/bin/screen #{screen_args.join(" ")} " \
|
121
|
+
"bash -c 'cd #{release_path} && #{SSHKit.config.command_map.prefix[:bundle].join(" ")} bundle exec process_bot #{process_bot_args.join(" ")}'"
|
126
122
|
|
127
123
|
puts "WARNING: A known bug prevents Sidekiq from starting when pty is set (which it is)" if fetch(:pty)
|
124
|
+
puts "ProcessBot Sidekiq command: #{command}"
|
128
125
|
|
129
126
|
backend.execute command
|
130
127
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class ProcessBot::ControlSocket
|
2
|
+
attr_reader :options, :process, :server
|
3
|
+
|
4
|
+
def initialize(options:, process:)
|
5
|
+
@options = options
|
6
|
+
@process = process
|
7
|
+
end
|
8
|
+
|
9
|
+
def port
|
10
|
+
options.fetch(:port).to_i
|
11
|
+
end
|
12
|
+
|
13
|
+
def start
|
14
|
+
require "socket"
|
15
|
+
|
16
|
+
@server = TCPServer.new(port)
|
17
|
+
end
|
18
|
+
|
19
|
+
def run_client_loop
|
20
|
+
Thread.new do
|
21
|
+
client = server.accept
|
22
|
+
|
23
|
+
Thread.new do
|
24
|
+
handle_client(client)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def handle_client(client)
|
30
|
+
command = JSON.parse(client.gets)
|
31
|
+
type = command.fetch("type")
|
32
|
+
|
33
|
+
if type == "stop"
|
34
|
+
process.stop
|
35
|
+
else
|
36
|
+
client.puts(JSON.generate(type: "error", message: "Unknown type: #{type}"))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class ProcessBot::Logger
|
2
|
+
attr_reader :fp_log, :options
|
3
|
+
|
4
|
+
def initialize(options:)
|
5
|
+
@options = options
|
6
|
+
|
7
|
+
open_file
|
8
|
+
end
|
9
|
+
|
10
|
+
def log(output)
|
11
|
+
fp_log&.write(output)
|
12
|
+
fp_log&.flush
|
13
|
+
end
|
14
|
+
|
15
|
+
def log_file_path
|
16
|
+
options.fetch(:log_file_path)
|
17
|
+
end
|
18
|
+
|
19
|
+
def open_file
|
20
|
+
@fp_log = File.open(log_file_path, "a")
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class ProcessBot::Options
|
2
|
+
attr_reader :options
|
3
|
+
|
4
|
+
def initialize(options = {})
|
5
|
+
@options = options
|
6
|
+
end
|
7
|
+
|
8
|
+
def fetch(*args, **opts, &blk)
|
9
|
+
options.fetch(*args, **opts, &blk)
|
10
|
+
end
|
11
|
+
|
12
|
+
def present?(key)
|
13
|
+
return true if options.key?(key) && options[key]
|
14
|
+
|
15
|
+
false
|
16
|
+
end
|
17
|
+
|
18
|
+
def set(key, value)
|
19
|
+
options[key] = value
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
class ProcessBot::Process::Handlers::Sidekiq
|
2
|
+
attr_reader :options
|
3
|
+
|
4
|
+
def initialize(options)
|
5
|
+
@options = options
|
6
|
+
|
7
|
+
set_defaults
|
8
|
+
end
|
9
|
+
|
10
|
+
def fetch(*args, **opts)
|
11
|
+
options.fetch(*args, **opts)
|
12
|
+
end
|
13
|
+
|
14
|
+
def set_option(key, value)
|
15
|
+
raise "Unknown option for Sidekiq handler: #{key}" unless options.key?(key)
|
16
|
+
|
17
|
+
set(key, value)
|
18
|
+
end
|
19
|
+
|
20
|
+
def set(*args, **opts)
|
21
|
+
options.set(*args, **opts)
|
22
|
+
end
|
23
|
+
|
24
|
+
def set_defaults
|
25
|
+
set :sidekiq_default_hooks, true
|
26
|
+
set :sidekiq_pid, -> { File.join(shared_path, "tmp", "pids", "sidekiq.pid") }
|
27
|
+
set :sidekiq_timeout, 10
|
28
|
+
set :sidekiq_roles, fetch(:sidekiq_role, :app)
|
29
|
+
set :sidekiq_processes, 1
|
30
|
+
set :sidekiq_options_per_process, nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def command # rubocop:disable Metrics/AbcSize
|
34
|
+
args = []
|
35
|
+
|
36
|
+
options.options.each do |key, value|
|
37
|
+
if (match = key.to_s.match(/\Asidekiq-(.+)\Z/))
|
38
|
+
sidekiq_key = match[1]
|
39
|
+
|
40
|
+
if sidekiq_key == "queue"
|
41
|
+
value.split(",").each do |queue|
|
42
|
+
args.push "--queue #{value}"
|
43
|
+
end
|
44
|
+
else
|
45
|
+
args.push "--#{sidekiq_key} #{value}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
command = ""
|
51
|
+
command << "#{options.fetch(:bundle_prefix)} " if options.present?(:bundle_prefix)
|
52
|
+
command << "bundle exec sidekiq #{args.compact.join(' ')}"
|
53
|
+
command
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
class ProcessBot::Process::Runner
|
2
|
+
attr_reader :command, :exit_status, :logger, :monitor, :options, :stop_time
|
3
|
+
|
4
|
+
def initialize(command:, logger:, options:)
|
5
|
+
@command = command
|
6
|
+
@logger = logger
|
7
|
+
@monitor = Monitor.new
|
8
|
+
@options = options
|
9
|
+
@output = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def output(output:, type:) # rubocop:disable Lint/UnusedMethodArgument
|
13
|
+
logger.log(output)
|
14
|
+
end
|
15
|
+
|
16
|
+
def run # rubocop:disable Metrics/AbcSize
|
17
|
+
@start_time = Time.new
|
18
|
+
stderr_reader, stderr_writer = IO.pipe
|
19
|
+
|
20
|
+
require "pty"
|
21
|
+
|
22
|
+
PTY.spawn(command, err: stderr_writer.fileno) do |stdout, _stdin, pid|
|
23
|
+
@pid = pid
|
24
|
+
logger.log "Command running with PID #{pid}: #{command}"
|
25
|
+
|
26
|
+
stdout_reader_thread = Thread.new do
|
27
|
+
stdout.each_char do |chunk|
|
28
|
+
monitor.synchronize do
|
29
|
+
output(type: :stdout, output: chunk)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
rescue Errno::EIO
|
33
|
+
# Process done
|
34
|
+
ensure
|
35
|
+
status = Process::Status.wait(@pid, 0)
|
36
|
+
|
37
|
+
@exit_status = status.exitstatus
|
38
|
+
stderr_writer.close
|
39
|
+
end
|
40
|
+
|
41
|
+
stderr_reader_thread = Thread.new do
|
42
|
+
stderr_reader.each_char do |chunk|
|
43
|
+
monitor.synchronize do
|
44
|
+
output(type: :stderr, output: chunk)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
stdout_reader_thread.join
|
50
|
+
stderr_reader_thread.join
|
51
|
+
|
52
|
+
@stop_time = Time.new
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/process_bot/process.rb
CHANGED
@@ -1,5 +1,52 @@
|
|
1
1
|
class ProcessBot::Process
|
2
|
-
|
3
|
-
|
2
|
+
autoload :Handlers, "#{__dir__}/process/handlers"
|
3
|
+
autoload :Runner, "#{__dir__}/process/runner"
|
4
|
+
|
5
|
+
attr_reader :options, :stopped
|
6
|
+
|
7
|
+
def initialize(options)
|
8
|
+
@options = options
|
9
|
+
@stopped = false
|
10
|
+
end
|
11
|
+
|
12
|
+
def logger
|
13
|
+
@logger ||= ProcessBot::Logger.new(options: options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def start_control_socket
|
17
|
+
@control_socket = ProcessBot::ControlSocket.new(options: options, process: self)
|
18
|
+
@control_socket.start
|
19
|
+
end
|
20
|
+
|
21
|
+
def stop
|
22
|
+
@stopped = true
|
23
|
+
end
|
24
|
+
|
25
|
+
def handler_class
|
26
|
+
@handler_class ||= begin
|
27
|
+
require_relative "process/handlers/#{options.fetch(:handler)}"
|
28
|
+
ProcessBot::Process::Handlers.const_get(StringCases.snake_to_camel(options.fetch(:handler)))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def execute!
|
33
|
+
start_control_socket
|
34
|
+
|
35
|
+
loop do
|
36
|
+
run
|
37
|
+
|
38
|
+
if stopped
|
39
|
+
break
|
40
|
+
else
|
41
|
+
puts "Process stopped - starting again after 1 sec"
|
42
|
+
sleep 1
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def run
|
48
|
+
handler_instance = handler_class.new(options)
|
49
|
+
runner = ProcessBot::Process::Runner.new(command: handler_instance.command, logger: logger, options: options)
|
50
|
+
runner.run
|
4
51
|
end
|
5
52
|
end
|
data/lib/process_bot/version.rb
CHANGED
data/lib/process_bot.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
require_relative "process_bot/version"
|
4
2
|
|
5
3
|
module ProcessBot
|
6
4
|
class Error < StandardError; end
|
7
|
-
|
5
|
+
|
6
|
+
autoload :Capistrano, "#{__dir__}/process_bot/capistrano"
|
7
|
+
autoload :ControlSocket, "#{__dir__}/process_bot/control_socket"
|
8
|
+
autoload :Logger, "#{__dir__}/process_bot/logger"
|
9
|
+
autoload :Options, "#{__dir__}/process_bot/options"
|
10
|
+
autoload :Process, "#{__dir__}/process_bot/process"
|
8
11
|
end
|
data/peak_flow.yml
ADDED
data/process_bot.gemspec
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/process_bot/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "process_bot"
|
7
|
+
spec.version = ProcessBot::VERSION
|
8
|
+
spec.authors = ["kaspernj"]
|
9
|
+
spec.email = ["k@spernj.org"]
|
10
|
+
|
11
|
+
spec.summary = "Run and control processes."
|
12
|
+
spec.description = "Run and control processes."
|
13
|
+
spec.homepage = "https://github.com/kaspernj/process_bot"
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.required_ruby_version = ">= 2.6.0"
|
16
|
+
|
17
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
18
|
+
|
19
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
20
|
+
spec.metadata["source_code_uri"] = "https://github.com/kaspernj/process_bot"
|
21
|
+
spec.metadata["changelog_uri"] = "https://github.com/kaspernj/process_bot/blob/master/CHANGELOG.md"
|
22
|
+
|
23
|
+
# Specify which files should be added to the gem when it is released.
|
24
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
25
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
26
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
27
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
28
|
+
end
|
29
|
+
end
|
30
|
+
spec.bindir = "exe"
|
31
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
32
|
+
spec.require_paths = ["lib"]
|
33
|
+
|
34
|
+
# Uncomment to register a new dependency of your gem
|
35
|
+
# spec.add_dependency "example-gem", "~> 1.0"
|
36
|
+
|
37
|
+
spec.add_development_dependency "rubocop"
|
38
|
+
spec.add_development_dependency "rubocop-performance"
|
39
|
+
spec.add_development_dependency "rubocop-rake"
|
40
|
+
spec.add_development_dependency "rubocop-rspec"
|
41
|
+
|
42
|
+
# For more information and examples about making a new gem, check out our
|
43
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
44
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
45
|
+
end
|
metadata
CHANGED
@@ -1,19 +1,76 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: process_bot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- kaspernj
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
12
|
-
dependencies:
|
11
|
+
date: 2022-10-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rubocop
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rubocop-performance
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubocop-rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubocop-rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
13
69
|
description: Run and control processes.
|
14
70
|
email:
|
15
71
|
- k@spernj.org
|
16
|
-
executables:
|
72
|
+
executables:
|
73
|
+
- process_bot
|
17
74
|
extensions: []
|
18
75
|
extra_rdoc_files: []
|
19
76
|
files:
|
@@ -21,17 +78,29 @@ files:
|
|
21
78
|
- ".rubocop.yml"
|
22
79
|
- CHANGELOG.md
|
23
80
|
- Gemfile
|
81
|
+
- Gemfile.lock
|
24
82
|
- LICENSE.txt
|
25
83
|
- README.md
|
26
84
|
- Rakefile
|
85
|
+
- exe/process_bot
|
27
86
|
- lib/process_bot.rb
|
87
|
+
- lib/process_bot/capistrano.rb
|
28
88
|
- lib/process_bot/capistrano/puma.rake
|
29
89
|
- lib/process_bot/capistrano/puma.rb
|
90
|
+
- lib/process_bot/capistrano/puma/common.rb
|
30
91
|
- lib/process_bot/capistrano/sidekiq.rake
|
31
92
|
- lib/process_bot/capistrano/sidekiq.rb
|
32
93
|
- lib/process_bot/capistrano/sidekiq_helpers.rb
|
94
|
+
- lib/process_bot/control_socket.rb
|
95
|
+
- lib/process_bot/logger.rb
|
96
|
+
- lib/process_bot/options.rb
|
33
97
|
- lib/process_bot/process.rb
|
98
|
+
- lib/process_bot/process/handlers.rb
|
99
|
+
- lib/process_bot/process/handlers/sidekiq.rb
|
100
|
+
- lib/process_bot/process/runner.rb
|
34
101
|
- lib/process_bot/version.rb
|
102
|
+
- peak_flow.yml
|
103
|
+
- process_bot.gemspec
|
35
104
|
- sig/process_bot.rbs
|
36
105
|
homepage: https://github.com/kaspernj/process_bot
|
37
106
|
licenses:
|
@@ -41,6 +110,7 @@ metadata:
|
|
41
110
|
homepage_uri: https://github.com/kaspernj/process_bot
|
42
111
|
source_code_uri: https://github.com/kaspernj/process_bot
|
43
112
|
changelog_uri: https://github.com/kaspernj/process_bot/blob/master/CHANGELOG.md
|
113
|
+
rubygems_mfa_required: 'true'
|
44
114
|
post_install_message:
|
45
115
|
rdoc_options: []
|
46
116
|
require_paths:
|
@@ -56,7 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
56
126
|
- !ruby/object:Gem::Version
|
57
127
|
version: '0'
|
58
128
|
requirements: []
|
59
|
-
rubygems_version: 3.
|
129
|
+
rubygems_version: 3.3.7
|
60
130
|
signing_key:
|
61
131
|
specification_version: 4
|
62
132
|
summary: Run and control processes.
|