daemon_runner 0.2.2 → 0.3.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 +4 -4
- data/.editorconfig +9 -0
- data/README.md +45 -0
- data/daemon_runner.gemspec +3 -0
- data/examples/example1.rb +24 -1
- data/lib/daemon_runner.rb +1 -0
- data/lib/daemon_runner/client.rb +91 -26
- data/lib/daemon_runner/session.rb +125 -0
- data/lib/daemon_runner/shell_out.rb +25 -3
- metadata +46 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d36f55746d2502664fad4104b312003f1b473b95
|
4
|
+
data.tar.gz: 6729f091a55d2ee3ebee5d0e72788589b88367c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6eaa76309f8b31a68ceb7ce508e7047c050fee14215f7330c28bf551f88c190bbcd37f3106aea7f595178441ab8560a5dcbffe852bf8a62fa0a75b515826a0d3
|
7
|
+
data.tar.gz: af1b9a90f5b429831c47b6df4091e175c493137d01b147bc9e43e1fce25e136167b0e64dade105b0884342e43ee25033ed8f8ade57fcbe22e27e4cb315a7a3b1
|
data/.editorconfig
ADDED
data/README.md
CHANGED
@@ -40,6 +40,8 @@ In order to use this gem you must subclass `DaemonRunner::Client` and add a few
|
|
40
40
|
* :error_sleep_time - Number of seconds to sleep before retying a failed task (**optional**, _default_: 5 seconds)
|
41
41
|
* :post_task_sleep_time - Number of seconds to sleep after each task (**optional**, _default_: 1 seconds)
|
42
42
|
|
43
|
+
* `schedule` - How often the task should run. See [Scheduling](#scheduling) below. (**optional**)
|
44
|
+
|
43
45
|
### Example
|
44
46
|
|
45
47
|
```ruby
|
@@ -102,6 +104,49 @@ service = MyService::Client.new(options)
|
|
102
104
|
service.start!
|
103
105
|
```
|
104
106
|
|
107
|
+
### Scheduling
|
108
|
+
Tasks can define the schedule that they run on and how their schedule is executed.
|
109
|
+
To do this, define a method named `schedule` with an array formatted as:
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
[:schedule_type, duration]
|
113
|
+
```
|
114
|
+
|
115
|
+
For example, if you wanted your task to run every 5 minutes, you would do the
|
116
|
+
following:
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
#!/usr/bin/env ruby
|
120
|
+
|
121
|
+
class MyService
|
122
|
+
class Tasks
|
123
|
+
class Quiz
|
124
|
+
def schedule
|
125
|
+
[:every, '5m']
|
126
|
+
end
|
127
|
+
|
128
|
+
def run!(args)
|
129
|
+
puts args
|
130
|
+
args
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
```
|
136
|
+
|
137
|
+
This would execute the `run!` method every 5 minutes. Duration can be defined as a
|
138
|
+
string in the `'<number>s/m/h/d/w'` format or as a number of seconds. Schedule types
|
139
|
+
are `:in, :at, :every, :cron, :interval`. See rufus-scheduler's
|
140
|
+
[README](https://github.com/jmettraux/rufus-scheduler#in-at-every-interval-cron)
|
141
|
+
for more information.
|
142
|
+
|
143
|
+
The default for tasks that don't explicitly define a schedule is
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
def schedule
|
147
|
+
[:interval, options[:loop_sleep_time]]
|
148
|
+
end
|
149
|
+
```
|
105
150
|
|
106
151
|
## Development
|
107
152
|
|
data/daemon_runner.gemspec
CHANGED
@@ -20,9 +20,12 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_dependency "logging", "~> 2.1"
|
22
22
|
spec.add_dependency "mixlib-shellout", "~> 2.2"
|
23
|
+
spec.add_dependency "diplomat", "~> 1.0"
|
24
|
+
spec.add_dependency "rufus-scheduler", "~> 3.2"
|
23
25
|
|
24
26
|
spec.add_development_dependency "bundler", "~> 1.12"
|
25
27
|
spec.add_development_dependency "rake", "~> 10.0"
|
26
28
|
spec.add_development_dependency "minitest", "~> 5.0"
|
27
29
|
spec.add_development_dependency "yard", "~> 0.8.7"
|
30
|
+
spec.add_development_dependency "dev-consul", "~> 0.6.4"
|
28
31
|
end
|
data/examples/example1.rb
CHANGED
@@ -16,6 +16,10 @@ end
|
|
16
16
|
class MyService
|
17
17
|
class Tasks
|
18
18
|
class Bar
|
19
|
+
def schedule
|
20
|
+
[:cron, '*/1 * * * *']
|
21
|
+
end
|
22
|
+
|
19
23
|
def run!(name)
|
20
24
|
puts name
|
21
25
|
name
|
@@ -28,6 +32,10 @@ class MyService
|
|
28
32
|
class Tasks
|
29
33
|
class Baz
|
30
34
|
class << self
|
35
|
+
def schedule
|
36
|
+
[:interval, 10]
|
37
|
+
end
|
38
|
+
|
31
39
|
def run!(args)
|
32
40
|
name = args[0]
|
33
41
|
reason = args[1]
|
@@ -40,13 +48,28 @@ class MyService
|
|
40
48
|
end
|
41
49
|
end
|
42
50
|
|
51
|
+
class MyService
|
52
|
+
class Tasks
|
53
|
+
class Quiz
|
54
|
+
def schedule
|
55
|
+
[:interval, '30s']
|
56
|
+
end
|
57
|
+
def foo!(args)
|
58
|
+
puts 'Firing error'
|
59
|
+
sargs
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
43
65
|
class MyService
|
44
66
|
class Client < DaemonRunner::Client
|
45
67
|
def tasks
|
46
68
|
[
|
47
69
|
[::MyService::Tasks::Foo.new, 'run!'],
|
48
70
|
[::MyService::Tasks::Bar.new, 'run!', 'bar'],
|
49
|
-
[::MyService::Tasks::Baz, 'run!', 'baz', 'because']
|
71
|
+
[::MyService::Tasks::Baz, 'run!', 'baz', 'because'],
|
72
|
+
[::MyService::Tasks::Quiz.new, 'foo!', 'blarg', 'assdg']
|
50
73
|
]
|
51
74
|
end
|
52
75
|
end
|
data/lib/daemon_runner.rb
CHANGED
data/lib/daemon_runner/client.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'rufus-scheduler'
|
2
|
+
|
1
3
|
module DaemonRunner
|
2
4
|
class Client
|
3
5
|
include Logger
|
@@ -9,6 +11,22 @@ module DaemonRunner
|
|
9
11
|
|
10
12
|
def initialize(options)
|
11
13
|
@options = options
|
14
|
+
|
15
|
+
# Set error handling
|
16
|
+
# @param [Rufus::Scheduler::Job] job job that raised the error
|
17
|
+
# @param [RuntimeError] error the body of the error
|
18
|
+
def scheduler.on_error(job, error)
|
19
|
+
error_sleep_time = job[:error_sleep_time]
|
20
|
+
logger = job[:logger]
|
21
|
+
task_id = job[:task_id]
|
22
|
+
|
23
|
+
logger.error "#{task_id}: #{error}"
|
24
|
+
logger.debug "#{task_id}: Suspending #{task_id} for #{error_sleep_time} seconds"
|
25
|
+
job.pause
|
26
|
+
sleep error_sleep_time
|
27
|
+
logger.debug "#{task_id}: Resuming #{task_id}"
|
28
|
+
job.resume
|
29
|
+
end
|
12
30
|
end
|
13
31
|
|
14
32
|
# Hook to allow initial setup tasks before running tasks.
|
@@ -33,7 +51,14 @@ module DaemonRunner
|
|
33
51
|
This must be an array of methods for the runner to call'
|
34
52
|
end
|
35
53
|
|
36
|
-
# @return [Fixnum]
|
54
|
+
# @return [Array<Symbol, String/Fixnum>] Schedule tuple-like with the type of schedule and its timing.
|
55
|
+
def schedule
|
56
|
+
# The default type is an `interval` which trigger, execute and then trigger again after
|
57
|
+
# the interval has elapsed.
|
58
|
+
[:interval, loop_sleep_time]
|
59
|
+
end
|
60
|
+
|
61
|
+
# @return [Fixnum] Number of seconds to sleep between loop interactions.
|
37
62
|
def loop_sleep_time
|
38
63
|
return @loop_sleep_time unless @loop_sleep_time.nil?
|
39
64
|
@loop_sleep_time = if options[:loop_sleep_time].nil?
|
@@ -68,22 +93,16 @@ module DaemonRunner
|
|
68
93
|
def start!
|
69
94
|
wait
|
70
95
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
sleep post_task_sleep_time
|
76
|
-
end
|
77
|
-
|
78
|
-
sleep loop_sleep_time
|
96
|
+
logger.warn 'Tasks list is empty' if tasks.empty?
|
97
|
+
tasks.each do |task|
|
98
|
+
run_task(task)
|
99
|
+
sleep post_task_sleep_time
|
79
100
|
end
|
80
101
|
|
81
|
-
|
82
|
-
|
83
|
-
logger.
|
84
|
-
|
85
|
-
sleep error_sleep_time
|
86
|
-
retry
|
102
|
+
scheduler.join
|
103
|
+
rescue SystemExit, Interrupt
|
104
|
+
logger.info 'Shutting down'
|
105
|
+
scheduler.shutdown
|
87
106
|
end
|
88
107
|
|
89
108
|
private
|
@@ -103,30 +122,76 @@ module DaemonRunner
|
|
103
122
|
end
|
104
123
|
|
105
124
|
out[:method] = task[1]
|
125
|
+
|
126
|
+
out[:task_id] = if out[:instance].respond_to?(:task_id)
|
127
|
+
out[:instance].send(:task_id).to_s
|
128
|
+
else
|
129
|
+
"#{out[:class_name]}.#{out[:method]}"
|
130
|
+
end
|
131
|
+
raise ArgumentError, 'Invalid task id' if out[:task_id].nil? || out[:task_id].empty?
|
132
|
+
|
106
133
|
out[:args] = task[2..-1].flatten
|
107
134
|
out
|
108
135
|
end
|
109
136
|
|
137
|
+
# @private
|
138
|
+
# @param [Class] instance an instance of the task class
|
139
|
+
# @return [Hash<Symbol, String>] schedule parsed in parts: Schedule type and timing
|
140
|
+
def parse_schedule(instance)
|
141
|
+
valid_types = [:in, :at, :every, :interval, :cron]
|
142
|
+
out = {}
|
143
|
+
task_schedule = if instance.respond_to?(:schedule)
|
144
|
+
instance.send(:schedule)
|
145
|
+
else
|
146
|
+
schedule
|
147
|
+
end
|
148
|
+
|
149
|
+
raise ArgumentError, 'Malformed schedule definition, should be [TYPE, DURATION]' if task_schedule.length < 2
|
150
|
+
raise ArgumentError, 'Invalid schedule type' unless valid_types.include?(task_schedule[0].to_sym)
|
151
|
+
|
152
|
+
out[:type] = task_schedule[0].to_sym
|
153
|
+
out[:schedule] = task_schedule[1]
|
154
|
+
out
|
155
|
+
end
|
156
|
+
|
110
157
|
# @private
|
111
158
|
# @param [Array<String, String, Array>] task to run
|
112
159
|
# @return [String] output returned from task
|
113
160
|
def run_task(task)
|
114
161
|
parsed_task = parse_task(task)
|
115
162
|
instance = parsed_task[:instance]
|
163
|
+
schedule = parse_schedule(instance)
|
116
164
|
class_name = parsed_task[:class_name]
|
117
165
|
method = parsed_task[:method]
|
118
166
|
args = parsed_task[:args]
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
167
|
+
task_id = parsed_task[:task_id]
|
168
|
+
|
169
|
+
# Schedule the task
|
170
|
+
schedule_log_line = "#{task_id}: Scheduling job #{class_name}.#{method} as `:#{schedule[:type]}` type"
|
171
|
+
schedule_log_line += " with schedule: #{schedule[:schedule]}"
|
172
|
+
logger.debug schedule_log_line
|
173
|
+
|
174
|
+
scheduler.send(schedule[:type], schedule[:schedule], :overlap => false, :job => true) do |job|
|
175
|
+
log_line = "#{task_id}: Running #{class_name}.#{method}"
|
176
|
+
log_line += "(#{args})" unless args.empty?
|
177
|
+
logger.debug log_line
|
178
|
+
|
179
|
+
job[:error_sleep_time] = error_sleep_time
|
180
|
+
job[:logger] = logger
|
181
|
+
job[:task_id] = task_id
|
182
|
+
|
183
|
+
out = if args.empty?
|
184
|
+
instance.send(method.to_sym)
|
185
|
+
else
|
186
|
+
instance.send(method.to_sym, args)
|
187
|
+
end
|
188
|
+
logger.debug "#{task_id}: Got: #{out}"
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# @return [Rufus::Scheduler] A scheduler instance
|
193
|
+
def scheduler
|
194
|
+
@scheduler ||= ::Rufus::Scheduler.new
|
130
195
|
end
|
131
196
|
end
|
132
197
|
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'diplomat'
|
2
|
+
|
3
|
+
module DaemonRunner
|
4
|
+
#
|
5
|
+
# Manage distributed locks with Consul
|
6
|
+
#
|
7
|
+
class Session
|
8
|
+
include Logger
|
9
|
+
|
10
|
+
class << self
|
11
|
+
attr_reader :session
|
12
|
+
|
13
|
+
def start(name, **options)
|
14
|
+
@session ||= Session.new(name, options).renew!
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
# Acquire a lock with the current session, or initialize a new session
|
19
|
+
#
|
20
|
+
# @param path [String] A path in the Consul key-value space to lock
|
21
|
+
# @param lock_session [Session] The Session instance to lock the lock to
|
22
|
+
# @return [Boolean] `true` if the lock was acquired
|
23
|
+
#
|
24
|
+
def lock(path)
|
25
|
+
Diplomat::Lock.acquire(path, session.id)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Release a lock held by the current session
|
29
|
+
#
|
30
|
+
# @param path [String] A path in the Consul key-value space to release
|
31
|
+
# @param lock_session [Session] The Session instance that the lock was acquired with
|
32
|
+
#
|
33
|
+
def release(path)
|
34
|
+
Diplomat::Lock.release(path, session.id)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Consul session ID
|
39
|
+
attr_reader :id
|
40
|
+
|
41
|
+
# Session name
|
42
|
+
attr_reader :name
|
43
|
+
|
44
|
+
# Period, in seconds, after which session expires
|
45
|
+
attr_reader :ttl
|
46
|
+
|
47
|
+
# Period, in seconds, that a session's locks will be
|
48
|
+
attr_reader :delay
|
49
|
+
|
50
|
+
# Behavior when a session is invalidated, can be set to either release or delete
|
51
|
+
attr_reader :behavior
|
52
|
+
|
53
|
+
# @param name [String] Session name
|
54
|
+
# @option options [Fixnum] ttl (15) Session TTL in seconds
|
55
|
+
# @option options [Fixnum] delay (15) Session release dealy in seconds
|
56
|
+
# @option options [String] behavior (release) Session release behavior
|
57
|
+
def initialize(name, **options)
|
58
|
+
logger.info('Initializing a Consul session')
|
59
|
+
|
60
|
+
@name = name
|
61
|
+
@ttl = options.fetch(:ttl, 15)
|
62
|
+
@delay = options.fetch(:delay, 15)
|
63
|
+
@behavior = options.fetch(:behavior, 'release')
|
64
|
+
|
65
|
+
init
|
66
|
+
end
|
67
|
+
|
68
|
+
# Check if there is an active renew thread
|
69
|
+
#
|
70
|
+
# @return [Boolean] `true` if the thread is alive
|
71
|
+
def renew?
|
72
|
+
@renew.is_a?(Thread) && @renew.alive?
|
73
|
+
end
|
74
|
+
|
75
|
+
# Create a thread to periodically renew the lock session
|
76
|
+
#
|
77
|
+
def renew!
|
78
|
+
return if renew?
|
79
|
+
|
80
|
+
@renew = Thread.new do
|
81
|
+
## Wakeup every TTL/2 seconds and renew the session
|
82
|
+
loop do
|
83
|
+
sleep ttl / 2
|
84
|
+
|
85
|
+
begin
|
86
|
+
logger.debug(" - Renewing Consul session #{id}")
|
87
|
+
Diplomat::Session.renew(id)
|
88
|
+
|
89
|
+
rescue Faraday::ResourceNotFound
|
90
|
+
logger.warn("Consul session #{id} has expired!")
|
91
|
+
|
92
|
+
init
|
93
|
+
rescue StandardError => e
|
94
|
+
## Keep the thread from exiting
|
95
|
+
logger.error(e)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
self
|
101
|
+
end
|
102
|
+
|
103
|
+
# Stop the renew thread and destroy the session
|
104
|
+
#
|
105
|
+
def destroy!
|
106
|
+
@renew.kill if renew?
|
107
|
+
Diplomat::Session.destroy(id)
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
# Initialize a session and store it's ID
|
113
|
+
#
|
114
|
+
def init
|
115
|
+
@id = Diplomat::Session.create(
|
116
|
+
:Name => name,
|
117
|
+
:TTL => "#{ttl}s",
|
118
|
+
:LockDelay => "#{delay}s",
|
119
|
+
:Behavior => behavior
|
120
|
+
)
|
121
|
+
|
122
|
+
logger.info(" - Initialized a Consul session #{id}")
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -3,17 +3,30 @@ require 'mixlib/shellout'
|
|
3
3
|
module DaemonRunner
|
4
4
|
class ShellOut
|
5
5
|
attr_reader :runner, :stdout
|
6
|
-
attr_reader :command, :cwd, :timeout, :wait
|
6
|
+
attr_reader :command, :cwd, :timeout, :wait, :valid_exit_codes
|
7
|
+
|
8
|
+
# Wait for the process with the given pid to finish
|
9
|
+
# @param pid [Fixnum] the pid to wait on
|
10
|
+
# @param flags [Fixnum] flags to Process.wait2
|
11
|
+
# @return [Process::Status, nil] the process status or nil if no process was found
|
12
|
+
def self.wait2(pid = nil, flags = 0)
|
13
|
+
return nil if pid.nil?
|
14
|
+
Process.wait2(pid, flags)[1]
|
15
|
+
rescue Errno::ECHILD
|
16
|
+
nil
|
17
|
+
end
|
7
18
|
|
8
19
|
# @param command [String] the command to run
|
9
20
|
# @param cwd [String] the working directory to run the command
|
10
21
|
# @param timeout [Fixnum] the command timeout
|
11
22
|
# @param wait [Boolean] wheather to wait for the command to finish
|
12
|
-
|
23
|
+
# @param valid_exit_codes [Array<Fixnum>] exit codes that aren't flagged as failures
|
24
|
+
def initialize(command: nil, cwd: '/tmp', timeout: 15, wait: true, valid_exit_codes: [0])
|
13
25
|
@command = command
|
14
26
|
@cwd = cwd
|
15
27
|
@timeout = timeout
|
16
28
|
@wait = wait
|
29
|
+
@valid_exit_codes = valid_exit_codes
|
17
30
|
end
|
18
31
|
|
19
32
|
# Run command
|
@@ -27,6 +40,13 @@ module DaemonRunner
|
|
27
40
|
end
|
28
41
|
end
|
29
42
|
|
43
|
+
# Wait for the process to finish
|
44
|
+
# @param flags [Fixnum] flags to Process.wait2
|
45
|
+
# @return [Process::Status, nil] the process status or nil if no process was found
|
46
|
+
def wait2(flags = 0)
|
47
|
+
self.class.wait2(@pid, flags)
|
48
|
+
end
|
49
|
+
|
30
50
|
private
|
31
51
|
|
32
52
|
# Run a command and wait for it to finish
|
@@ -45,9 +65,10 @@ module DaemonRunner
|
|
45
65
|
# @return [Fixnum] process id
|
46
66
|
def run_and_detach
|
47
67
|
log_r, log_w = IO.pipe
|
48
|
-
Process.spawn(command, pgroup: true, err: :out, out: log_w)
|
68
|
+
@pid = Process.spawn(command, pgroup: true, err: :out, out: log_w)
|
49
69
|
log_r.close
|
50
70
|
log_w.close
|
71
|
+
@pid
|
51
72
|
end
|
52
73
|
|
53
74
|
# Validate command is defined before trying to start the command
|
@@ -74,6 +95,7 @@ module DaemonRunner
|
|
74
95
|
# @return [Mixlib::ShellOut] client
|
75
96
|
def runner
|
76
97
|
@runner ||= Mixlib::ShellOut.new(command, :cwd => cwd, :timeout => timeout)
|
98
|
+
@runner.valid_exit_codes = valid_exit_codes
|
77
99
|
end
|
78
100
|
end
|
79
101
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: daemon_runner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Thompson
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-10-
|
11
|
+
date: 2016-10-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: logging
|
@@ -38,6 +38,34 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '2.2'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: diplomat
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rufus-scheduler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.2'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.2'
|
41
69
|
- !ruby/object:Gem::Dependency
|
42
70
|
name: bundler
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,6 +122,20 @@ dependencies:
|
|
94
122
|
- - "~>"
|
95
123
|
- !ruby/object:Gem::Version
|
96
124
|
version: 0.8.7
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: dev-consul
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 0.6.4
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 0.6.4
|
97
139
|
description:
|
98
140
|
email:
|
99
141
|
- Andrew_Thompson@rapid7.com
|
@@ -101,6 +143,7 @@ executables: []
|
|
101
143
|
extensions: []
|
102
144
|
extra_rdoc_files: []
|
103
145
|
files:
|
146
|
+
- ".editorconfig"
|
104
147
|
- ".gitignore"
|
105
148
|
- ".travis.yml"
|
106
149
|
- CODE_OF_CONDUCT.md
|
@@ -116,6 +159,7 @@ files:
|
|
116
159
|
- lib/daemon_runner.rb
|
117
160
|
- lib/daemon_runner/client.rb
|
118
161
|
- lib/daemon_runner/logger.rb
|
162
|
+
- lib/daemon_runner/session.rb
|
119
163
|
- lib/daemon_runner/shell_out.rb
|
120
164
|
- lib/daemon_runner/version.rb
|
121
165
|
homepage: https://github.com/rapid7/daemon_runner/
|