foreverb 0.2.1 → 0.2.2
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.
- data/CHANGES.md +9 -0
- data/README.md +106 -7
- data/bin/foreverb +89 -20
- data/examples/sample +33 -33
- data/lib/forever.rb +2 -0
- data/lib/forever/base.rb +21 -3
- data/lib/forever/version.rb +1 -1
- metadata +6 -4
data/CHANGES.md
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# Version 0.2.2
|
2
|
+
|
3
|
+
* Added global monitoring, to easily watch each `foreverb` daemon
|
4
|
+
* Look daemons through config file and unix command `ps`
|
5
|
+
* Added `start` CLI command
|
6
|
+
* Added `restart` CLI command
|
7
|
+
* Added `tail` CLI command
|
8
|
+
* Added `update` CLI command (useful to update daemons config)
|
9
|
+
* Improved documentation (aka the readme)
|
data/README.md
CHANGED
@@ -207,17 +207,42 @@ you should see:
|
|
207
207
|
[14/07 15:48:40] Bye bye
|
208
208
|
```
|
209
209
|
|
210
|
-
##
|
210
|
+
## CLI
|
211
211
|
|
212
|
-
|
212
|
+
### Help:
|
213
|
+
|
214
|
+
``` sh
|
215
|
+
$ foreverb help
|
216
|
+
Tasks:
|
217
|
+
foreverb help [TASK] # Describe available tasks or one specific task
|
218
|
+
foreverb list # List Forever running daemons
|
219
|
+
foreverb restart [DAEMON] [--all] [--yes] # Restart one or more matching daemons
|
220
|
+
foreverb start [DAEMON] [--all] [--yes] # Start one or more matching daemons
|
221
|
+
foreverb stop [DAEMON] [--all] [--yes] # Stop one or more matching daemons
|
222
|
+
foreverb tail [DAEMON] # Tail log of first matching daemon
|
223
|
+
foreverb update [DAEMON] [--all] [--yes] # Update config from one or more matching daemons
|
224
|
+
foreverb version # show the version number
|
225
|
+
```
|
226
|
+
|
227
|
+
### List daemons:
|
213
228
|
|
214
229
|
``` sh
|
215
230
|
$ foreverb list
|
216
|
-
|
217
|
-
|
231
|
+
RUNNING /Developer/src/Extras/githubwatcher/bin/githubwatcher
|
232
|
+
RUNNING /Developer/src/Extras/foreverb/examples/sample
|
233
|
+
Reading config from: /Users/DAddYE/.foreverb
|
234
|
+
```
|
235
|
+
|
236
|
+
### Monitor daemons (with ps):
|
237
|
+
|
238
|
+
``` sh
|
239
|
+
$ foreverb list -m
|
240
|
+
PID RSS CPU CMD
|
241
|
+
5528 168 Mb 0.1 % Forever: /Developer/src/Extras/githubwatcher/bin/githubwatcher
|
242
|
+
5541 18 Mb 0.0 % Forever: /Developer/src/Extras/foreverb/examples/sample
|
218
243
|
```
|
219
244
|
|
220
|
-
Stop daemon(s):
|
245
|
+
### Stop daemon(s):
|
221
246
|
|
222
247
|
``` sh
|
223
248
|
$ foreverb stop foo
|
@@ -229,7 +254,65 @@ Killing process Forever: /usr/bin/githubwatcher with pid 2824
|
|
229
254
|
Killing process Forever: examples/sample with pid 2836
|
230
255
|
```
|
231
256
|
|
232
|
-
|
257
|
+
### Start daemon(s):
|
258
|
+
|
259
|
+
``` sh
|
260
|
+
$ foreverb start github
|
261
|
+
Do you want really start /Developer/src/Extras/githubwatcher/bin/githubwatcher? y
|
262
|
+
=> Found pid 5528...
|
263
|
+
=> Killing process 5528...
|
264
|
+
=> Process demonized with pid 14925 with Forever v.0.2.2
|
265
|
+
```
|
266
|
+
|
267
|
+
as for stop we allow `--all` and `-y`
|
268
|
+
|
269
|
+
### Restart daemon(s)
|
270
|
+
|
271
|
+
``` sh
|
272
|
+
$ foreverb restart github
|
273
|
+
Do you want really restart /Developer/src/Extras/githubwatcher/bin/githubwatcher? y
|
274
|
+
=> Found pid 5528...
|
275
|
+
=> Killing process 5528...
|
276
|
+
=> Process demonized with pid 14925 with Forever v.0.2.2
|
277
|
+
```
|
278
|
+
|
279
|
+
as for stop we allow `--all` and `-y`
|
280
|
+
|
281
|
+
### Tail logs
|
282
|
+
|
283
|
+
``` sh
|
284
|
+
$ foreverb tail github
|
285
|
+
[22/07 11:22:17] Quering git://github.com/DAddYE/lipsiadmin.git...
|
286
|
+
[22/07 11:22:17] Quering git://github.com/DAddYE/lightbox.git...
|
287
|
+
[22/07 11:22:17] Quering git://github.com/DAddYE/exception-notifier.git...
|
288
|
+
[22/07 11:22:17] Quering git://github.com/DAddYE/lipsiablog.git...
|
289
|
+
[22/07 11:22:17] Quering git://github.com/DAddYE/purple_ruby.git...
|
290
|
+
```
|
291
|
+
|
292
|
+
you can specify how many lines show with option `-n`, default is `150`
|
293
|
+
|
294
|
+
### Update config
|
295
|
+
|
296
|
+
This command would be helpful if you change `pid` `log` path, in this way the global config file `~/.foreverb` will be update
|
297
|
+
using latest informations from yours deamons
|
298
|
+
|
299
|
+
Note that you can personalize the config file setting `FOREVER_PATH` matching your needs.
|
300
|
+
|
301
|
+
``` sh
|
302
|
+
$ foreverb update github
|
303
|
+
Do you want really update config from /Developer/src/Extras/githubwatcher/bin/githubwatcher? y
|
304
|
+
```
|
305
|
+
|
306
|
+
as for stop we allow `--all` and `-y`
|
307
|
+
|
308
|
+
## HACKS
|
309
|
+
|
310
|
+
Bundler has the bad behavior to load `Gemfile` from your current path, so if your `daemons` (ex: [githubwatcher](https://github.com/daddye/githubwatcher))
|
311
|
+
is shipped with their own `Gemfile` to prevent errors you must insert that line:
|
312
|
+
|
313
|
+
``` ruby
|
314
|
+
ENV['BUNDLE_GEMFILE'] = File.expand_path('../../Gemfile', __FILE__) # edit matching your Gemfile path
|
315
|
+
```
|
233
316
|
|
234
317
|
## Extras
|
235
318
|
|
@@ -237,4 +320,20 @@ To see a most comprensive app running _foreverb_ + _growl_ see [githubwatcher ge
|
|
237
320
|
|
238
321
|
## Author
|
239
322
|
|
240
|
-
DAddYE, you can follow me on twitter [@daddye](http://twitter.com/daddye) or take a look at my site [daddye.it](http://www.daddye.it)
|
323
|
+
DAddYE, you can follow me on twitter [@daddye](http://twitter.com/daddye) or take a look at my site [daddye.it](http://www.daddye.it)
|
324
|
+
|
325
|
+
## Copyright
|
326
|
+
|
327
|
+
Copyright (C) 2011 Davide D'Agostino - [@daddye](http://twitter.com/daddye)
|
328
|
+
|
329
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
330
|
+
associated documentation files (the “Software”), to deal in the Software without restriction, including without
|
331
|
+
limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
332
|
+
and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
333
|
+
|
334
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
335
|
+
|
336
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
337
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM,
|
338
|
+
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
339
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/bin/foreverb
CHANGED
@@ -2,35 +2,81 @@
|
|
2
2
|
require 'rubygems' unless defined?(Gem)
|
3
3
|
require File.expand_path('../../lib/forever/version.rb', __FILE__)
|
4
4
|
require 'thor'
|
5
|
+
require 'yaml'
|
5
6
|
|
6
|
-
|
7
|
+
FOREVER_PATH = ENV['FOREVER_PATH'] ||= File.expand_path("~/.foreverb") unless defined?(FOREVER_PATH)
|
7
8
|
|
9
|
+
class CLI < Thor
|
8
10
|
|
9
|
-
desc "list", "List Forever daemons"
|
11
|
+
desc "list", "List Forever running daemons"
|
12
|
+
method_option :monitor, :type => :boolean, :aliases => "-m", :default => false, :desc => "Show memory and cpu usage with ps"
|
10
13
|
def list
|
11
|
-
say "
|
12
|
-
|
14
|
+
say "No deamons running", :red if config.empty?
|
15
|
+
|
16
|
+
if options.monitor
|
17
|
+
print_table([%w(PID RSS CPU CMD), *ps])
|
18
|
+
else
|
19
|
+
config.each do |conf|
|
20
|
+
status = begin
|
21
|
+
"WRONG CONFIG" and return unless File.exist?(conf[:pid])
|
22
|
+
pid = File.read(conf[:pid]).to_i
|
23
|
+
Process.kill(0, pid)
|
24
|
+
"RUNNING"
|
25
|
+
rescue Errno::ESRCH, Errno::ENOENT
|
26
|
+
"NOT RUNNING"
|
27
|
+
end
|
28
|
+
say_status status, conf[:file], status =~ /^RUNNING/ ? :green : :red
|
29
|
+
end
|
30
|
+
say "Reading config from: #{FOREVER_PATH}", :blue
|
31
|
+
end
|
13
32
|
end
|
14
33
|
|
15
|
-
desc "stop [DAEMON] [--all] [--yes]", "Stop
|
16
|
-
method_option :all, :type => :boolean, :aliases => "-a", :desc => "
|
17
|
-
method_option :yes, :type => :boolean, :aliases => "-y", :desc => "Don't ask permission to kill
|
34
|
+
desc "stop [DAEMON] [--all] [--yes]", "Stop one or more matching daemons"
|
35
|
+
method_option :all, :type => :boolean, :aliases => "-a", :desc => "All matching daemons"
|
36
|
+
method_option :yes, :type => :boolean, :aliases => "-y", :desc => "Don't ask permission to kill daemon"
|
18
37
|
def stop(daemon=nil)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
found.each do |daemon|
|
25
|
-
daemon = daemon.split("\t").map(&:strip)
|
26
|
-
if options.yes || yes?("Do you want really stop \e[1m#{daemon[-1]}\e[0m with pid \e[1m#{daemon[0]}\e[0m?")
|
27
|
-
say "Killing process \e[1m#{daemon[-1]}\e[0m\e[32m with pid \e[1m#{daemon[0]}", :green
|
28
|
-
result = `kill #{daemon[0]}`.strip
|
29
|
-
say result, :red if result != ""
|
38
|
+
find(daemon, :multiple => options.all).each do |conf|
|
39
|
+
if options.yes || yes?("Do you want really stop \e[1m#{conf[:file]}\e[0m?")
|
40
|
+
say_status "STOPPING", conf[:file]
|
41
|
+
system(conf[:file], 'stop')
|
42
|
+
say_status "ERROR", result, :red if result != ""
|
30
43
|
end
|
31
44
|
end
|
32
45
|
end
|
33
46
|
|
47
|
+
desc "start [DAEMON] [--all] [--yes]", "Start one or more matching daemons"
|
48
|
+
method_option :all, :type => :boolean, :aliases => "-a", :desc => "All matching daemons"
|
49
|
+
method_option :yes, :type => :boolean, :aliases => "-y", :desc => "Don't ask permission to start the daemon"
|
50
|
+
def start(daemon=nil)
|
51
|
+
find(daemon, :multiple => options.all).each do |conf|
|
52
|
+
system(conf[:file]) if options.yes || yes?("Do you want really start \e[1m#{conf[:file]}\e[0m?")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
desc "restart [DAEMON] [--all] [--yes]", "Restart one or more matching daemons"
|
57
|
+
method_option :all, :type => :boolean, :aliases => "-a", :desc => "All matching daemons"
|
58
|
+
method_option :yes, :type => :boolean, :aliases => "-y", :desc => "Don't ask permission to start the daemon"
|
59
|
+
def restart(daemon=nil)
|
60
|
+
invoke :start
|
61
|
+
end
|
62
|
+
|
63
|
+
desc "tail [DAEMON]", "Tail log of first matching daemon"
|
64
|
+
method_option :lines, :aliases => "-n", :default => 150, :desc => "How many lines show?"
|
65
|
+
def tail(daemon)
|
66
|
+
found = find(daemon)[0]
|
67
|
+
return unless found
|
68
|
+
system "tail -f -n #{options.lines} #{found[:log]}"
|
69
|
+
end
|
70
|
+
|
71
|
+
desc "update [DAEMON] [--all] [--yes]", "Update config from one or more matching daemons"
|
72
|
+
method_option :all, :type => :boolean, :aliases => "-a", :desc => "All matching daemons"
|
73
|
+
method_option :yes, :type => :boolean, :aliases => "-y", :desc => "Don't ask permission to start the daemon"
|
74
|
+
def update(daemon=nil)
|
75
|
+
find(daemon, :multiple => options.all).each do |conf|
|
76
|
+
system(conf[:file], 'up') if options.yes || yes?("Do you want really update config from \e[1m#{conf[:file]}\e[0m?")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
34
80
|
map "--version" => :version
|
35
81
|
desc "version", "show the version number"
|
36
82
|
def version
|
@@ -38,8 +84,31 @@ class CLI < Thor
|
|
38
84
|
end
|
39
85
|
|
40
86
|
private
|
41
|
-
def
|
42
|
-
|
87
|
+
def find(daemon, options={})
|
88
|
+
multiple = options.delete(:multiple)
|
89
|
+
say "You must provide a daemon name or provide --all option", :red and return [] if daemon.nil? && !multiple
|
90
|
+
found = multiple ? config : config.find_all { |conf| conf[:file] =~ /#{daemon}/ }
|
91
|
+
say "Daemon(s) matching '#{daemon}' not found", :red if found.empty? && !daemon.nil?
|
92
|
+
say "Daemons not found", :red if found.empty? && nil && daemon.nil?
|
93
|
+
found
|
94
|
+
end
|
95
|
+
|
96
|
+
def find_all(daemon)
|
97
|
+
find(daemon, :multiple => true)
|
98
|
+
end
|
99
|
+
|
100
|
+
def config
|
101
|
+
File.exist?(FOREVER_PATH) ? YAML.load_file(FOREVER_PATH) : []
|
102
|
+
end
|
103
|
+
|
104
|
+
def ps
|
105
|
+
# This is horrible command, but how we can keep compatiblity between darwin and *unix ?
|
106
|
+
result = `ps axo pid,rss,pcpu,command | grep -vE "^USER|grep" | grep Forever: | awk '{print $1"\t"$2"\t"$3"\t"$4" "$5" "$6}'`
|
107
|
+
result = result.chomp.split("\n").map { |line| line.split("\t") }
|
108
|
+
result = result.sort { |a,b| b[1].to_i <=> a[1].to_i }
|
109
|
+
result.each { |column| column[1] = "%d Mb" % [column[1].to_i / 1024] }
|
110
|
+
result.each { |column| column[2] = "%s %" % [column[2]] }
|
111
|
+
result
|
43
112
|
end
|
44
113
|
end
|
45
114
|
|
data/examples/sample
CHANGED
@@ -10,42 +10,42 @@ Forever.run do
|
|
10
10
|
puts "All jobs will will wait me for 1 second"; sleep 1
|
11
11
|
end
|
12
12
|
|
13
|
-
every 5.seconds, :last => Time.now do
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
every 30.seconds, :last => Time.now do
|
18
|
-
|
19
|
-
|
20
|
-
end
|
21
|
-
|
22
|
-
every 10.seconds, :at => "#{Time.now.hour}:00" do
|
23
|
-
|
24
|
-
end
|
25
|
-
|
26
|
-
every 1.seconds, :at => "#{Time.now.hour}:#{Time.now.min+1}" do
|
27
|
-
|
28
|
-
end
|
29
|
-
|
13
|
+
# every 5.seconds, :last => Time.now do
|
14
|
+
# puts "Every 5 seconds from start"
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# every 30.seconds, :last => Time.now do
|
18
|
+
# puts "Every 30 seconds from start with boom"
|
19
|
+
# raise "woooooa"
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# every 10.seconds, :at => "#{Time.now.hour}:00" do
|
23
|
+
# puts "Every 10 seconds but first call at #{Time.now.hour}:00"
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# every 1.seconds, :at => "#{Time.now.hour}:#{Time.now.min+1}" do
|
27
|
+
# puts "Every one second but first call at #{Time.now.hour}:#{Time.now.min}"
|
28
|
+
# end
|
29
|
+
#
|
30
30
|
every 10.seconds do
|
31
31
|
puts "Every 10 second"
|
32
32
|
end
|
33
|
-
|
34
|
-
every 20.seconds do
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
every 15.seconds do
|
39
|
-
|
40
|
-
end
|
41
|
-
|
42
|
-
every 10.seconds, :at => [":#{Time.now.min+1}", ":#{Time.now.min+2}"] do
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
|
-
on_error do |e|
|
47
|
-
|
48
|
-
end
|
33
|
+
#
|
34
|
+
# every 20.seconds do
|
35
|
+
# puts "Every 20 second"
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# every 15.seconds do
|
39
|
+
# puts "Every 15 seconds, but my task require 10 seconds"; sleep 10
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# every 10.seconds, :at => [":#{Time.now.min+1}", ":#{Time.now.min+2}"] do
|
43
|
+
# puts "Every 10 seconds but first call at xx:#{Time.now.min}"
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# on_error do |e|
|
47
|
+
# puts "Boom raised: #{e.message}"
|
48
|
+
# end
|
49
49
|
|
50
50
|
on_exit do
|
51
51
|
puts "Bye bye"
|
data/lib/forever.rb
CHANGED
data/lib/forever/base.rb
CHANGED
@@ -14,15 +14,27 @@ module Forever
|
|
14
14
|
Dir.mkdir(File.dirname(log)) if log && !File.exist?(File.dirname(log))
|
15
15
|
Dir.mkdir(File.dirname(pid)) if pid && !File.exist?(File.dirname(pid))
|
16
16
|
|
17
|
+
write_config!
|
18
|
+
|
19
|
+
if ARGV.any? { |arg| arg == "config" }
|
20
|
+
print config.to_yaml
|
21
|
+
return
|
22
|
+
end
|
23
|
+
|
24
|
+
return if ARGV.any? { |arg| arg == "up" }
|
25
|
+
|
17
26
|
stop!
|
18
27
|
|
19
|
-
return if ARGV
|
28
|
+
return if ARGV.any? { |arg| arg == "stop" }
|
20
29
|
|
21
30
|
fork do
|
22
31
|
$0 = "Forever: #{$0}"
|
23
32
|
print "=> Process demonized with pid #{Process.pid} with Forever v.#{Forever::VERSION}\n"
|
24
33
|
|
25
34
|
%w(INT TERM KILL).each { |signal| trap(signal) { stop! } }
|
35
|
+
trap(:HUP) do
|
36
|
+
IO.open(1, 'w'){ |s| s.puts config }
|
37
|
+
end
|
26
38
|
|
27
39
|
File.open(pid, "w") { |f| f.write(Process.pid.to_s) } if pid
|
28
40
|
|
@@ -124,11 +136,17 @@ module Forever
|
|
124
136
|
alias :inspect :to_s
|
125
137
|
|
126
138
|
def config
|
127
|
-
{ :dir => dir, :file => file, :log => log, :pid => pid }
|
139
|
+
{ :dir => dir, :file => file, :log => log, :pid => pid }
|
128
140
|
end
|
129
|
-
alias :to_yaml :config
|
130
141
|
|
131
142
|
private
|
143
|
+
def write_config!
|
144
|
+
config_was = File.exist?(FOREVER_PATH) ? YAML.load_file(FOREVER_PATH) : []
|
145
|
+
config_was.delete_if { |conf| conf[:file] == file }
|
146
|
+
config_was << config
|
147
|
+
File.open(FOREVER_PATH, "w") { |f| f.write config_was.to_yaml }
|
148
|
+
end
|
149
|
+
|
132
150
|
def exists?(*values)
|
133
151
|
values.all? { |value| value && File.exist?(value) }
|
134
152
|
end
|
data/lib/forever/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreverb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 2
|
10
|
+
version: 0.2.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- DAddYE
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-07-
|
18
|
+
date: 2011-07-22 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -45,11 +45,13 @@ extra_rdoc_files: []
|
|
45
45
|
|
46
46
|
files:
|
47
47
|
- .gitignore
|
48
|
+
- CHANGES.md
|
48
49
|
- Gemfile
|
49
50
|
- README.md
|
50
51
|
- Rakefile
|
51
52
|
- bin/foreverb
|
52
53
|
- examples/sample
|
54
|
+
- examples/tmp/sample.pid
|
53
55
|
- foreverb.gemspec
|
54
56
|
- lib/forever.rb
|
55
57
|
- lib/forever/base.rb
|