foreverb 0.2.6 → 0.3.0.a

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES.md CHANGED
@@ -1,3 +1,9 @@
1
+ # Version 0.3.0 - October 4, 2011
2
+
3
+ * Added fork backend
4
+ * Improved queue
5
+ * Added before/after each/all filters
6
+
1
7
  # Version 0.2.6 - August 27, 2011
2
8
 
3
9
  * Added back support for update the daemon config
data/README.md CHANGED
@@ -14,6 +14,8 @@ In my servers I've several daemons and what I need is:
14
14
  * easily manage exceptions
15
15
  * easily see logs
16
16
  * easily start/stop/restart daemon
17
+ * no blocking jobs
18
+ * no blocking queue
17
19
 
18
20
  As like [sinatra](https://github.com/sinatra/sinatra) and [padrino](https://github.com/padrino/padrino-framework) I need a
19
21
  **thin** framework to do these jobs in few seconds. This mean that:
@@ -61,7 +63,7 @@ Forever.run do
61
63
  end
62
64
  end
63
65
 
64
- on_ready do
66
+ before :each do # or if you prefer before :all
65
67
  require 'bundler/setup'
66
68
  require 'foo'
67
69
  Foo.start_loop
@@ -124,7 +126,7 @@ So looking our [example](https://github.com/DAddYE/foreverb/blob/master/examples
124
126
  Forever.run do
125
127
  dir File.expand_path('../', __FILE__) # Default is ../../__FILE__
126
128
 
127
- on_ready do
129
+ before :all do
128
130
  puts "All jobs will will wait me for 1 second"; sleep 1
129
131
  end
130
132
 
@@ -146,6 +148,7 @@ Forever.run do
146
148
 
147
149
  every 15.seconds do
148
150
  puts "Every 15 seconds, but my task require 10 seconds"; sleep 10
151
+ # This doesn't block other jobs and your queue !!!!!!!
149
152
  end
150
153
 
151
154
  every 10.seconds, :at => [":#{Time.now.min+1}", ":#{Time.now.min+2}"] do
@@ -207,6 +210,30 @@ you should see:
207
210
  [14/07 15:48:40] Bye bye
208
211
  ```
209
212
 
213
+ ## Filters
214
+
215
+ In foreverb we have a couple of filters, `before` and `after`, like rspec you should be able to filter `before :all` or `before :each`.
216
+
217
+ ``` rb
218
+ before :all do
219
+ puts "This will be ran only at start"
220
+ end
221
+
222
+ before :each do
223
+ puts "Do that before each job"
224
+ end
225
+
226
+ # ... here jobs ...
227
+
228
+ after :all do
229
+ puts "This will be ran only at shutdown"
230
+ end
231
+
232
+ after :each do
233
+ puts "Do that after each job"
234
+ end
235
+ ```
236
+
210
237
  ## CLI
211
238
 
212
239
  ### Help:
@@ -307,6 +334,8 @@ as for stop we allow `--all` and `-y`
307
334
 
308
335
  ## HACKS
309
336
 
337
+ ### Bundler
338
+
310
339
  Bundler has the bad behavior to load `Gemfile` from your current path, so if your `daemons` (ex: [githubwatcher](https://github.com/daddye/githubwatcher))
311
340
  is shipped with their own `Gemfile` to prevent errors you must insert that line:
312
341
 
@@ -314,6 +343,37 @@ is shipped with their own `Gemfile` to prevent errors you must insert that line:
314
343
  ENV['BUNDLE_GEMFILE'] = File.expand_path('../../Gemfile', __FILE__) # edit matching your Gemfile path
315
344
  ```
316
345
 
346
+ ### Rails/Padrino prevent memory leaks
347
+
348
+ I highly suggest to use `fork` and `before` filters when you are using `forever` with frameworks, this since running same job on our ruby will eat a lot of
349
+ ram, so the better way that I found is that:
350
+
351
+ ```rb
352
+ Forever.run :fork => true do
353
+ before :each do
354
+ require '/config/boot' # here the rails/padrino environment
355
+ end
356
+
357
+ every 10.seconds, :at => ['12:00', '00:00'] do
358
+ Project.all(&:perform_long_task)
359
+ end
360
+
361
+ every 1.minute do
362
+ Account.all.map(&:send_emails)
363
+ end
364
+ end
365
+ ```
366
+
367
+ This is similar to create a new process i.e.:
368
+
369
+ ```rb
370
+ Process.fork do
371
+ require '/config/boot'
372
+ my_long_jobs
373
+ end
374
+ Process.waitall
375
+ ```
376
+
317
377
  ## Extras
318
378
 
319
379
  To see a most comprensive app running _foreverb_ + _growl_ see [githubwatcher gem](https://github.com/daddye/githubwatcher)
@@ -336,4 +396,4 @@ The above copyright notice and this permission notice shall be included in all c
336
396
  THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
337
397
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM,
338
398
  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.
399
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'rubygems' unless defined?(Gem)
2
2
  require 'bundler/gem_tasks'
3
3
  require 'rspec/core/rake_task'
4
+ require 'rake/testtask'
4
5
 
5
6
  %w(install release).each do |task|
6
7
  Rake::Task[task].enhance do
@@ -8,9 +9,9 @@ require 'rspec/core/rake_task'
8
9
  end
9
10
  end
10
11
 
11
- desc "Bump version on github"
12
+ desc 'Bump version on github'
12
13
  task :bump do
13
- if `git status -s`.strip == ""
14
+ if `git status -s`.strip == ''
14
15
  puts "\e[31mNothing to commit (working directory clean)\e[0m"
15
16
  else
16
17
  version = Bundler.load_gemspec(Dir[File.expand_path('../*.gemspec', __FILE__)].first).version
@@ -18,13 +19,22 @@ task :bump do
18
19
  end
19
20
  end
20
21
 
21
- task :release => :bump
22
+ Rake::TestTask.new(:spec) do |t|
23
+ t.test_files = Dir['spec/**/*_spec.rb']
24
+ t.verbose = true
25
+ end
22
26
 
23
- desc "Run complete application spec suite"
24
- RSpec::Core::RakeTask.new("spec") do |t|
25
- t.skip_bundler = true
26
- t.pattern = './spec/**/*_spec.rb'
27
- t.rspec_opts = %w(-fs --color --fail-fast)
27
+ namespace :example do
28
+ Dir['./examples/*'].each do |path|
29
+ next if File.directory?(path)
30
+ name = File.basename(path)
31
+ desc "Run example #{name}"
32
+ task name, :fork do |t, args|
33
+ ENV['FORK'] = args[:fork]
34
+ exec "#{Gem.ruby} #{path} && sleep 3 && tail -f -n 150 #{path}/../log/#{name}.log; #{path} stop"
35
+ end
36
+ end
28
37
  end
29
38
 
39
+ task :release => :bump
30
40
  task :default => :spec
@@ -3,7 +3,7 @@ require 'rubygems' unless defined?(Gem)
3
3
  require 'bundler/setup'
4
4
  require 'forever'
5
5
 
6
- Forever.run do
6
+ Forever.run :fork => ENV['FORK'] do
7
7
  dir File.expand_path('../', __FILE__) # Default is ../../__FILE__
8
8
 
9
9
  every 5.seconds do
@@ -14,19 +14,11 @@ Forever.run do
14
14
  puts "All jobs will will wait me for 1 second"; sleep 1
15
15
  end
16
16
 
17
- every 5.seconds, :last => Time.now do
18
- puts "Every 5 seconds from start"
19
- end
20
-
21
- every 30.seconds, :last => Time.now do
17
+ every 30.seconds do
22
18
  puts "Every 30 seconds from start with boom"
23
19
  raise "woooooa"
24
20
  end
25
21
 
26
- every 10.seconds, :at => "#{Time.now.hour}:00" do
27
- puts "Every 10 seconds but first call at #{Time.now.hour}:00"
28
- end
29
-
30
22
  every 1.seconds, :at => "#{Time.now.hour}:#{Time.now.min+1}" do
31
23
  puts "Every one second but first call at #{Time.now.hour}:#{Time.now.min}"
32
24
  end
@@ -40,7 +32,7 @@ Forever.run do
40
32
  end
41
33
 
42
34
  every 15.seconds do
43
- puts "Every 15 seconds, but my task require 10 seconds"; sleep 10
35
+ puts "Every 15 seconds, but my task requires 10 seconds"; sleep 10
44
36
  end
45
37
 
46
38
  every 10.seconds, :at => [":#{Time.now.min+1}", ":#{Time.now.min+2}"] do
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/ruby
2
+ require 'rubygems' unless defined?(Gem)
3
+ require 'bundler/setup'
4
+ require 'forever'
5
+
6
+ Forever.run :fork => ENV['FORK'] do
7
+ dir File.expand_path('../', __FILE__) # Default is ../../__FILE__
8
+
9
+ before :each do
10
+ puts 'before all'
11
+ end
12
+
13
+ after :each do
14
+ puts 'after all'
15
+ end
16
+
17
+ every 1.seconds do
18
+ puts 'wait me 10 seconds'; sleep 10
19
+ end
20
+
21
+ every 2.seconds do
22
+ puts 'every 2 seconds'
23
+ end
24
+
25
+ on_ready do
26
+ puts "All jobs will will wait me for 1 second"; sleep 1
27
+ end
28
+
29
+ on_exit do
30
+ puts "Bye bye"
31
+ end
32
+ end
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/ruby
2
+ require 'rubygems' unless defined?(Gem)
3
+ require 'bundler/setup'
4
+ require 'forever'
5
+
6
+ Forever.run :fork => ENV['FORK'] do
7
+ dir File.expand_path('../', __FILE__) # Default is ../../__FILE__
8
+
9
+ (1..40).each do |i|
10
+ every(i.seconds) { puts 'Every %d seconds' % i; sleep i }
11
+ end
12
+ end
@@ -18,5 +18,5 @@ Gem::Specification.new do |s|
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = %w(lib)
20
20
  s.add_dependency 'thor', '~>0.14.6'
21
- s.add_development_dependency 'rspec', '~>2.6.0'
21
+ s.add_development_dependency 'minitest'
22
22
  end
@@ -1,10 +1,10 @@
1
1
  require 'yaml' unless defined?(YAML)
2
- require "forever/extensions"
3
- require "forever/every"
4
- require "forever/base"
5
- require "forever/version"
2
+ require 'forever/extensions'
3
+ require 'forever/every'
4
+ require 'forever/base'
5
+ require 'forever/version'
6
6
 
7
- YAML::ENGINE.yamler = "syck" if defined?(YAML::ENGINE)
7
+ YAML::ENGINE.yamler = 'syck' if defined?(YAML::ENGINE)
8
8
 
9
9
  FOREVER_PATH = ENV['FOREVER_PATH'] ||= File.expand_path("~/.foreverb") unless defined?(FOREVER_PATH)
10
10
  path = File.dirname(FOREVER_PATH)
@@ -15,8 +15,8 @@ module Forever
15
15
 
16
16
  def run(options={}, &block)
17
17
  caller_file = caller(1).map { |line| line.split(/:(?=\d|in )/)[0,1] }.flatten.first
18
- options[:dir] ||= File.expand_path('../../', caller_file) # => we presume we are calling it from a bin|script dir
19
- options[:file] ||= File.expand_path(caller_file)
18
+ options[:file] ||= File.expand_path(caller_file)
19
+ options[:dir] ||= File.expand_path('../../', options[:file]) # => we presume we are calling it from a bin|script dir
20
20
  Base.new(options, &block)
21
21
  end # run
22
- end # Forever
22
+ end # Forever
@@ -4,12 +4,18 @@ module Forever
4
4
 
5
5
  class Base
6
6
  include Every
7
+ attr_reader :started_at
7
8
 
8
9
  def initialize(options={}, &block)
10
+ forking = options.delete(:fork)
11
+
12
+ # Run others methods
9
13
  options.each { |k,v| send(k, v) }
10
14
 
11
15
  instance_eval(&block)
12
16
 
17
+ raise 'No jobs defined!' if jobs.empty?
18
+
13
19
  Dir.chdir(dir) if exists?(dir)
14
20
  Dir.mkdir(File.dirname(log)) if log && !File.exist?(File.dirname(log))
15
21
  Dir.mkdir(File.dirname(pid)) if pid && !File.exist?(File.dirname(pid))
@@ -48,9 +54,13 @@ module Forever
48
54
  exit
49
55
  end
50
56
 
57
+ # Enable REE - http://www.rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
58
+ GC.copy_on_write_friendly = true if GC.respond_to?(:copy_on_write_friendly=)
59
+
51
60
  fork do
52
61
  $0 = "Forever: #{$0}"
53
- print "[\e[90m%s\e[0m] Process demonized with pid \e[1m%d\e[0m with Forever v.%s\n" % [name, Process.pid, Forever::VERSION]
62
+ print "[\e[90m%s\e[0m] Process demonized with pid \e[1m%d\e[0m with \e[1m%s\e[0m and Forever v.%s\n" %
63
+ [name, Process.pid, forking ? :fork : :thread, Forever::VERSION]
54
64
 
55
65
  %w(INT TERM KILL).each { |signal| trap(signal) { stop! } }
56
66
  trap(:HUP) do
@@ -65,27 +75,34 @@ module Forever
65
75
  STDOUT.reopen(stream)
66
76
  STDERR.reopen(STDOUT)
67
77
 
68
- threads = []
69
- safe_call(on_ready) if on_ready
70
- started_at = Time.now
71
-
72
- jobs.each do |job|
73
- threads << Thread.new do
74
- loop do
75
- break if File.exist?(stop_txt) && File.mtime(stop_txt) > started_at
76
- job.time?(Time.now) ? safe_call(job) : sleep(1)
78
+ @started_at = Time.now
79
+
80
+ # Invoke our before :all filters
81
+ before_filters[:all].each { |block| safe_call(block) }
82
+
83
+ # Start deamons
84
+ until stopping?
85
+ if forking
86
+ begin
87
+ jobs.select { |job| job.time?(Time.now) }.each do |job|
88
+ Process.fork { job_call(job) }
89
+ end
90
+ rescue Errno::EAGAIN
91
+ puts "\n\nWait all processes since os cannot create a new one\n\n"
92
+ Process.waitall
77
93
  end
94
+ else
95
+ jobs.each { |job| Thread.new { job_call(job) } if job.time?(Time.now) }
78
96
  end
97
+ sleep 0.5
79
98
  end
80
99
 
81
- # Launch our workers
82
- threads.map(&:join)
83
-
84
100
  # If we are here it means we are exiting so we can remove the pid and pending stop.txt
85
101
  FileUtils.rm_f(pid)
86
102
  FileUtils.rm_f(stop_txt)
87
103
 
88
- on_exit.call if on_exit
104
+ # Invoke our after :all filters
105
+ after_filters[:all].each { |block| safe_call(block) }
89
106
  end
90
107
 
91
108
  self
@@ -141,7 +158,7 @@ module Forever
141
158
  pid_was = File.read(pid).to_i
142
159
  FileUtils.rm_f(pid)
143
160
  print "[\e[90m%s\e[0m] Killing process \e[1m%d\e[0m...\n" % [name, pid_was]
144
- on_exit.call if on_exit
161
+ after_filters[:all].each { |block| safe_call(block) }
145
162
  Process.kill(:KILL, pid_was)
146
163
  else
147
164
  print "[\e[90m%s\e[0m] Process with \e[1mnot found\e[0m" % name
@@ -174,14 +191,14 @@ module Forever
174
191
  # Callback raised when at exit
175
192
  #
176
193
  def on_exit(&block)
177
- block_given? ? @_on_exit = block : @_on_exit
194
+ after(:all, &block)
178
195
  end
179
196
 
180
197
  ##
181
198
  # Callback to fire when the daemon start (blocking, not in thread)
182
199
  #
183
200
  def on_ready(&block)
184
- block_given? ? @_on_ready = block : @_on_ready
201
+ before(:all, &block)
185
202
  end
186
203
 
187
204
  ##
@@ -214,29 +231,58 @@ module Forever
214
231
  { :dir => dir, :file => file, :log => log, :pid => pid }
215
232
  end
216
233
 
217
- private
218
- def write_config!
219
- config_was = File.exist?(FOREVER_PATH) ? YAML.load_file(FOREVER_PATH) : []
220
- config_was.delete_if { |conf| conf[:file] == file }
221
- config_was << config
222
- File.open(FOREVER_PATH, "w") { |f| f.write config_was.to_yaml }
223
- end
234
+ def before(filter, &block)
235
+ raise "Filter #{filter.inspect} not supported, available options are: :each, :all" unless [:each, :all].include?(filter)
236
+ before_filters[filter] << block
237
+ end
224
238
 
225
- def exists?(*values)
226
- values.all? { |value| value && File.exist?(value) }
227
- end
239
+ def after(filter, &block)
240
+ raise "Filter #{filter.inspect} not supported, available options are: :each, :all" unless [:each, :all].include?(filter)
241
+ after_filters[filter] << block
242
+ end
228
243
 
229
- def safe_call(block)
230
- begin
231
- block.call
232
- rescue Exception => e
233
- puts "\n\n%s\n %s\n\n" % [e.message, e.backtrace.join("\n ")]
234
- on_error[e] if on_error
235
- end
236
- end
244
+ private
245
+ def before_filters
246
+ @_before_filters ||= Hash.new { |hash, k| hash[k] = [] }
247
+ end
237
248
 
238
- def stop_txt
239
- @_stop_txt ||= File.join(dir, 'stop.txt')
249
+ def after_filters
250
+ @_after_filters ||= Hash.new { |hash, k| hash[k] = [] }
251
+ end
252
+
253
+ def stopping?
254
+ File.exist?(stop_txt) && File.mtime(stop_txt) > started_at
255
+ end
256
+
257
+ def write_config!
258
+ config_was = File.exist?(FOREVER_PATH) ? YAML.load_file(FOREVER_PATH) : []
259
+ config_was.delete_if { |conf| conf[:file] == file }
260
+ config_was << config
261
+ File.open(FOREVER_PATH, "w") { |f| f.write config_was.to_yaml }
262
+ end
263
+
264
+ def exists?(*values)
265
+ values.all? { |value| value && File.exist?(value) }
266
+ end
267
+
268
+ def job_call(job)
269
+ return unless job.time?(Time.now)
270
+ before_filters[:each].each { |block| safe_call(block) }
271
+ safe_call(job)
272
+ after_filters[:each].each { |block| safe_call(block) }
273
+ end
274
+
275
+ def safe_call(block)
276
+ begin
277
+ block.call
278
+ rescue Exception => e
279
+ puts "\n\n%s\n %s\n\n" % [e.message, e.backtrace.join("\n ")]
280
+ on_error[e] if on_error
240
281
  end
282
+ end
283
+
284
+ def stop_txt
285
+ @_stop_txt ||= File.join(dir, 'stop.txt')
286
+ end
241
287
  end # Base
242
288
  end # Forever
@@ -1,26 +1,39 @@
1
+ require 'tmpdir'
2
+
1
3
  module Forever
2
4
  module Every
3
5
  class Job
4
- attr_accessor :period, :option, :last, :running
5
6
 
6
7
  def initialize(period, options, block)
7
- @period, @options, @running = period, options, false
8
- @at = options[:at] ? parse_at(*@options[:at]) : []
9
- @last = options[:last].to_i
10
- @block = block
8
+ @period = period
9
+ @at_start = options[:at] == :start && options.delete(:at) ? true : false
10
+ @at = options[:at] ? parse_at(*options[:at]) : []
11
+ @tmp = File.join(Dir.tmpdir, '%x' % rand(255**10))
12
+ @block = block
11
13
  end
12
14
 
13
15
  def call
14
- @last, @running = Time.now, true
16
+ File.open(@tmp, 'w') { |f| f.write('running') }
17
+ FileUtils.touch(@tmp)
15
18
  @block.call
16
19
  ensure
17
- @running = false
20
+ File.open(@tmp, 'w') { |f| f.write('idle') }
21
+ end
22
+
23
+ def running?
24
+ File.exist?(@tmp) && File.read(@tmp) == 'running'
25
+ end
26
+
27
+ def last
28
+ File.mtime(@tmp)
29
+ rescue Errno::ENOENT
30
+ 0
18
31
  end
19
32
 
20
33
  def time?(t)
21
- ellapsed_ready = (t - @last).to_i >= @period
34
+ elapsed_ready = (t - last).to_i >= @period
22
35
  time_ready = @at.empty? || @at.any? { |at| (at[0].empty? || t.hour == at[0].to_i) && (at[1].empty? || t.min == at[1].to_i) }
23
- !running && ellapsed_ready && time_ready
36
+ !running? && elapsed_ready && time_ready
24
37
  end
25
38
 
26
39
  private
@@ -43,4 +56,4 @@ module Forever
43
56
  @_jobs ||= []
44
57
  end
45
58
  end # Every
46
- end # Forever
59
+ end # Forever
@@ -1,3 +1,3 @@
1
1
  module Forever
2
- VERSION = "0.2.6" unless defined?(Forever::VERSION)
2
+ VERSION = "0.3.0.a" unless defined?(Forever::VERSION)
3
3
  end
@@ -1,34 +1,34 @@
1
- require 'spec_helper'
1
+ require File.expand_path('../spec_helper', __FILE__)
2
2
 
3
- describe "CLI" do
4
-
5
- it "should list no daemons" do
6
- cli('list').should match(/Your config is empty/)
7
- cli('list').should match(FOREVER_PATH)
8
- cli('list -m').should match(/PID RSS CPU CMD/)
3
+ describe 'CLI' do
4
+ def cli(task)
5
+ `#{Gem.ruby} #{File.expand_path('../../bin/foreverb', __FILE__)} #{task}`
9
6
  end
10
7
 
11
- it "should list a daemon" do
8
+ it 'should list daemons' do
9
+ cli('list').must_match(/Your config is empty/)
10
+ cli('list').must_match(FOREVER_PATH)
11
+ cli('list -m').must_match(/PID RSS CPU CMD/)
12
12
  run_example
13
- cli('list').should match(/RUNNING/)
14
- cli('list -m').should match(/Forever:\s/)
13
+ cli('list').must_match(/RUNNING/)
14
+ cli('list -m').must_match(/Forever:\s/)
15
15
  end
16
16
 
17
17
  it "should stop daemons" do
18
18
  run_example
19
- cli('list').should match(/RUNNING/)
19
+ cli('list').must_match(/RUNNING/)
20
20
  result = cli('stop -a -y')
21
- result.should match(/STOPPING/)
22
- result.should_not match(/ERROR/)
23
- cli('list').should match(/NOT RUNNING/)
21
+ result.must_match(/STOPPING/)
22
+ result.wont_match(/ERROR/)
23
+ cli('list').must_match(/NOT RUNNING/)
24
24
  end
25
25
 
26
- it "should kill daemons" do
26
+ it 'should kill daemons' do
27
27
  run_example
28
- cli('list').should match(/RUNNING/)
28
+ cli('list').must_match(/RUNNING/)
29
29
  result = cli('kill -a -y')
30
- result.should match(/KILLING/)
31
- result.should_not match(/ERROR/)
32
- cli('list').should match(/NOT RUNNING/)
30
+ result.must_match(/KILLING/)
31
+ result.wont_match(/ERROR/)
32
+ cli('list').must_match(/NOT RUNNING/)
33
33
  end
34
34
  end
@@ -1,48 +1,48 @@
1
- require 'spec_helper'
1
+ require File.expand_path('../spec_helper', __FILE__)
2
2
 
3
3
  describe Forever do
4
4
 
5
- before :each do
6
- $stdout = StringIO.new
7
- ARGV << 'up'
8
- end
9
-
10
5
  it 'should set a basic config' do
11
- @forever = Forever.run {}
12
- @forever.dir.should == File.expand_path("../../", __FILE__)
13
- @forever.log.should == File.join(@forever.dir, 'log', File.basename(__FILE__) + '.log')
14
- @forever.pid.should == File.join(@forever.dir, 'tmp', File.basename(__FILE__) + '.pid')
15
- @forever.file.should == __FILE__
6
+ run_example
7
+ @forever.dir.must_equal File.expand_path("../../", __FILE__)
8
+ @forever.log.must_equal File.join(@forever.dir, 'log', File.basename(example_filename, '.*') + '.log')
9
+ @forever.pid.must_equal File.join(@forever.dir, 'tmp', File.basename(example_filename, '.*') + '.pid')
10
+ @forever.file.must_equal example_filename
16
11
  config = YAML.load_file(FOREVER_PATH)
17
- config[0][:file].should == __FILE__
18
- config[0][:log].should == @forever.log
19
- config[0][:pid].should == @forever.pid
12
+ config[0][:file].must_equal example_filename
13
+ config[0][:log].must_equal @forever.log
14
+ config[0][:pid].must_equal @forever.pid
20
15
  end
21
16
 
22
17
  it 'should set a custom config' do
23
- @forever = Forever.run do
24
- dir File.expand_path('../', __FILE__)
25
- end
26
- @forever.dir.should == File.expand_path('../', __FILE__)
27
- @forever.log.should == File.join(@forever.dir, 'log', File.basename(__FILE__) + '.log')
28
- @forever.pid.should == File.join(@forever.dir, 'tmp', File.basename(__FILE__) + '.pid')
29
- @forever.file.should == __FILE__
18
+ run_example(:dir => Dir.tmpdir)
19
+ @forever.dir.must_equal Dir.tmpdir
20
+ @forever.log.must_equal File.join(@forever.dir, 'log', File.basename(example_filename, '.*') + '.log')
21
+ @forever.pid.must_equal File.join(@forever.dir, 'tmp', File.basename(example_filename, '.*') + '.pid')
22
+ @forever.file.must_equal example_filename
30
23
  config = YAML.load_file(FOREVER_PATH)
31
- config[0][:file].should == __FILE__
32
- config[0][:log].should == @forever.log
33
- config[0][:pid].should == @forever.pid
24
+ config[0][:file].must_equal example_filename
25
+ config[0][:log].must_equal @forever.log
26
+ config[0][:pid].must_equal @forever.pid
27
+ end
28
+
29
+ it 'should launch a daemon with threads with soft stop' do
30
+ run_example
31
+ sleep 0.1 while !File.exist?(@forever.pid)
32
+ pid = File.read(@forever.pid).to_i
33
+ sleep 1
34
+ out, err = capture_io { @forever.stop }
35
+ out.must_match(/waiting the daemon's death/i)
36
+ out.must_match(/#{pid}/)
34
37
  end
35
38
 
36
- it 'should launch a daemon' do
37
- ARGV.clear
38
- stdout_was, $stdout = $stdout, StringIO.new
39
- @forever = Forever.run do
40
- on_ready { sleep 2 }
41
- end
39
+ it 'should launch a daemon with threads with soft stop' do
40
+ run_example(:fork => true)
42
41
  sleep 0.1 while !File.exist?(@forever.pid)
43
42
  pid = File.read(@forever.pid).to_i
44
- Process.waitpid(pid)
45
- $stdout.string.should match(/not found/i)
46
- $stdout = stdout_was
43
+ sleep 1
44
+ out, err = capture_io { @forever.stop }
45
+ out.must_match(/waiting the daemon's death/i)
46
+ out.must_match(/#{pid}/)
47
47
  end
48
48
  end
@@ -1,48 +1,36 @@
1
1
  FOREVER_PATH = ENV['FOREVER_PATH'] ||= File.expand_path("../tmp/db.yaml", __FILE__)
2
2
  require 'rubygems' unless defined?(Gem)
3
3
  require 'bundler/setup'
4
- require 'rspec'
4
+ require 'minitest/autorun'
5
5
  require 'forever'
6
6
  require 'fileutils'
7
+ require 'tmpdir'
7
8
 
8
- module Helper
9
- def capture_stdout(&block)
10
- stdout_was, $stdout = $stdout, StringIO.new
11
- block.call
12
- return $stdout
13
- ensure
14
- $stdout = stdout_was
15
- end
9
+ $dir = File.expand_path('.')
16
10
 
17
- def run_example
18
- capture_stdout do
19
- @forever = Forever.run do
20
- on_ready { sleep }
21
- end
22
- end
11
+ class MiniTest::Spec
12
+ def run_example(options={}, &block)
13
+ block = proc { every(1.second) { puts 'foo' } } unless block_given?
14
+ capture_io { @forever = Forever.run(options, &block) }
23
15
  end
24
16
 
25
- def cli(task)
26
- output = `#{Gem.ruby} #{File.expand_path('../../bin/foreverb', __FILE__)} #{task}`
27
- end
28
- end
29
-
30
- RSpec.configure do |config|
31
- config.include(Helper)
17
+ let(:example_filename) { File.expand_path(__FILE__) }
32
18
 
33
- config.before :each do
19
+ before do
20
+ Dir.chdir($dir)
34
21
  FileUtils.rm_rf File.dirname(FOREVER_PATH)
35
22
  Dir.mkdir File.dirname(FOREVER_PATH)
36
23
  ARGV.clear
37
24
  end
38
25
 
39
- config.after :each do
26
+ after do
40
27
  FileUtils.rm_rf(File.dirname(FOREVER_PATH))
41
28
  if @forever
42
- capture_stdout { @forever.stop! }
29
+ capture_io { @forever.stop! }
43
30
  FileUtils.rm_rf(File.dirname(@forever.log)) if @forever.log
44
31
  FileUtils.rm_rf(File.dirname(@forever.pid)) if @forever.pid
45
32
  end
33
+ Dir.chdir($dir)
46
34
  ARGV.clear
47
35
  end
48
36
  end
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreverb
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
5
- prerelease:
4
+ hash: 50
5
+ prerelease: 6
6
6
  segments:
7
7
  - 0
8
- - 2
9
- - 6
10
- version: 0.2.6
8
+ - 3
9
+ - 0
10
+ - a
11
+ version: 0.3.0.a
11
12
  platform: ruby
12
13
  authors:
13
14
  - DAddYE
@@ -15,7 +16,7 @@ autorequire:
15
16
  bindir: bin
16
17
  cert_chain: []
17
18
 
18
- date: 2011-08-27 00:00:00 +02:00
19
+ date: 2011-10-04 00:00:00 +02:00
19
20
  default_executable:
20
21
  dependencies:
21
22
  - !ruby/object:Gem::Dependency
@@ -35,19 +36,17 @@ dependencies:
35
36
  type: :runtime
36
37
  version_requirements: *id001
37
38
  - !ruby/object:Gem::Dependency
38
- name: rspec
39
+ name: minitest
39
40
  prerelease: false
40
41
  requirement: &id002 !ruby/object:Gem::Requirement
41
42
  none: false
42
43
  requirements:
43
- - - ~>
44
+ - - ">="
44
45
  - !ruby/object:Gem::Version
45
- hash: 23
46
+ hash: 3
46
47
  segments:
47
- - 2
48
- - 6
49
48
  - 0
50
- version: 2.6.0
49
+ version: "0"
51
50
  type: :development
52
51
  version_requirements: *id002
53
52
  description: Small daemon framework for ruby, with logging, error handler, scheduling and much more.
@@ -66,7 +65,10 @@ files:
66
65
  - README.md
67
66
  - Rakefile
68
67
  - bin/foreverb
69
- - examples/sample
68
+ - examples/complex
69
+ - examples/simple
70
+ - examples/stress
71
+ - examples/tmp/complex.pid
70
72
  - foreverb.gemspec
71
73
  - lib/forever.rb
72
74
  - lib/forever/base.rb
@@ -97,12 +99,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
97
99
  required_rubygems_version: !ruby/object:Gem::Requirement
98
100
  none: false
99
101
  requirements:
100
- - - ">="
102
+ - - ">"
101
103
  - !ruby/object:Gem::Version
102
- hash: 3
104
+ hash: 25
103
105
  segments:
104
- - 0
105
- version: "0"
106
+ - 1
107
+ - 3
108
+ - 1
109
+ version: 1.3.1
106
110
  requirements: []
107
111
 
108
112
  rubyforge_project: foreverb