ngauthier-active-listener 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -20,14 +20,15 @@ This gem allows you to define tasks that can be run at specific time intervals.
20
20
  ### Add a config file
21
21
  In your rails project, add a config file like this:
22
22
 
23
-
24
23
  ---
25
24
  tasks:
26
25
  - task: my:rake:task
27
26
  period: 5
27
+ - task: my:other:rake:task
28
+ period: 14
28
29
 
29
30
 
30
- This instructs active-listener to run "rake my:rake:task" every 5 seconds.
31
+ This instructs active-listener to run "rake my:rake:task" every 5 seconds and "rake my:other:rake:task" every 14 seconds.
31
32
 
32
33
  Usually, these config files go in RAILS_ROOT/config/active-listener.yml.
33
34
 
@@ -44,36 +45,9 @@ Create a file in the initializers directory, like RAILS_ROOT/config/initializers
44
45
 
45
46
  This will use the config file "config/active-listener.yml". It will put the log file in "log/active-listener.log" and the pid file for tracking the process in "log/active-listener.pid".
46
47
 
47
- ### Special Handling of ActiveListener rake tasks that depend on the rails environment
48
- The scheme devised in the previous sections will generate an infinite loop if your Active Listener rake task(s) depend(s) on the rails environment being loaded. This occurs because we have added the initializer code into config/initializers, which gets loaded every time the environment is loaded. In order to avoid this, we can set a global variable that is queried in the initializer, providing conditional load behavior. Now, our initializer looks like this:
49
-
50
- if RAILS_ENV == "production" && !$active_listener_activated
51
- require 'active-listener'
52
- ActiveListener.autostart(
53
- :config => File.join(RAILS_ROOT, 'config', 'active-listener.yml'),
54
- :log_file => File.join(RAILS_ROOT, 'log', "active-listener-#{RAILS_ENV}.log"),
55
- :pid_file => File.join(RAILS_ROOT, 'log', "active-listener-#{RAILS_ENV}.pid"),
56
- :rake_root => File.join(RAILS_ROOT)
57
- )
58
- end
59
-
60
- And our Active Listener rake task (found in lib/tasks/active-listener.rake) looks like:
61
-
62
- desc "Helper to preclude infinite loop when a listener task depends on the rails environment"
63
- task :set_active_listener_active do
64
- $active_listener_activated = true
65
- end
66
-
67
- namespace :listeners do
68
- desc "Close games that have ended"
69
- task :game_end => [:set_active_listener_active, :environment] do
70
- # Logic as dictated by your app's needs
71
- end
72
- end
73
-
74
48
  ## Usage
75
49
 
76
- Active Listener will automatically start whenever the rails environment is loaded. It will replace an existing instance of active-listener if the pid file is the same and there is one running.
50
+ Active Listener will automatically start whenever the rails environment is loaded. It will not start if there is one already running with the pid in the pid file.
77
51
 
78
52
  So, you don't need to run the executable, it will "autostart" thanks to the initializer. Keep in mind this means that it will be running during your tests, development server, production, and any other environments you have. If you run your tests, the daemon keeps going after the tests are done. It doesn't stop when the server stops.
79
53
 
@@ -83,9 +57,6 @@ If you want to stop active-listener, run:
83
57
 
84
58
  active-listener --stop log/active-listener.pid
85
59
 
86
- Make sure to point it to your pid file.
87
-
88
-
89
60
  ## Other notes
90
61
  This gem uses Jeweler.
91
62
 
@@ -1,4 +1,4 @@
1
1
  ---
2
- :minor: 2
3
- :patch: 3
4
2
  :major: 0
3
+ :minor: 3
4
+ :patch: 0
@@ -28,6 +28,6 @@ if @al.events.empty?
28
28
  end
29
29
 
30
30
  while running
31
- @al.fire_events
32
- @al.sleep_to_next_event
31
+ @al.fire_events if @al.time_to_next_event < 0
32
+ sleep(0.2)
33
33
  end
@@ -13,7 +13,6 @@ class ActiveListener
13
13
  rescue
14
14
  raise "Need :config :pid_file :log_file :rake_root"
15
15
  end
16
- ActiveListener.stop(opts)
17
16
  command = [
18
17
  "start-stop-daemon --start",
19
18
  "--make-pidfile --pidfile #{pid_file}",
@@ -30,7 +29,7 @@ class ActiveListener
30
29
 
31
30
  def self.stop(opts = {})
32
31
  pid_file = opts[:pid_file]
33
- `start-stop-daemon --stop --oknodo --quiet --pidfile #{File.expand_path(pid_file)}`
32
+ `start-stop-daemon --stop --oknodo --pidfile #{File.expand_path(pid_file)}`
34
33
  end
35
34
 
36
35
  def initialize(opts = {})
@@ -52,24 +51,28 @@ class ActiveListener
52
51
  log("Firing event: #{evt.inspect}")
53
52
  log(evt.fire(:rake_root => rake_root))
54
53
  end
54
+ self.events.sort{|x,y| x.time_to_fire <=> y.time_to_fire}
55
55
  end
56
56
 
57
- def sleep_to_next_event
58
- self.events.sort{|x,y| x.time_to_fire <=> y.time_to_fire}
57
+ def time_to_next_event
59
58
  if self.events.first
60
59
  sleep_time = self.events.first.time_to_fire+0.01
61
60
  else
62
61
  sleep_time = 0.5
63
62
  end
64
- log("Sleeping for #{sleep_time}")
65
- sleep(sleep_time)
63
+ return sleep_time
64
+ end
65
+
66
+ def sleep_to_next_event
67
+ log("Sleeping for #{time_to_next_event}")
68
+ sleep(time_to_next_event)
66
69
  end
67
70
 
68
71
  class Event
69
72
  def initialize(opts = {})
70
73
  self.task = opts[:task] || opts["task"]
71
74
  self.period = opts[:period] || opts["period"]
72
- self.last_fire = 0
75
+ self.last_fire = Time.now.to_f
73
76
  end
74
77
 
75
78
  def time_to_fire
@@ -44,12 +44,13 @@ class ActiveListenerTest < Test::Unit::TestCase
44
44
 
45
45
  should "touch a file" do
46
46
  assert !File.exists?(@sample_file)
47
+ @al.sleep_to_next_event
47
48
  @al.fire_events
48
49
  assert File.exists?(@sample_file)
49
50
  end
50
51
 
51
- should "need to be fired when added" do
52
- assert @al.events[0].time_to_fire < 0
52
+ should "not need to be fired when added" do
53
+ assert @al.events[0].time_to_fire > 0
53
54
  end
54
55
 
55
56
  should "need to be fired 1 second after being fired" do
@@ -80,6 +81,7 @@ class ActiveListenerTest < Test::Unit::TestCase
80
81
  @al = ActiveListener.new(:config => @config_path)
81
82
  assert @al.events.size > 0
82
83
  assert !File.exists?(@sample_file)
84
+ @al.sleep_to_next_event
83
85
  @al.fire_events
84
86
  assert File.exists?(@sample_file)
85
87
  end
@@ -89,7 +91,7 @@ class ActiveListenerTest < Test::Unit::TestCase
89
91
  context "An autostarted listener" do
90
92
 
91
93
  setup do
92
- ActiveListener.autostart(
94
+ assert ActiveListener.autostart(
93
95
  :config => File.join(File.dirname(__FILE__), 'active_listener.yml'),
94
96
  :pid_file => File.join(File.dirname(__FILE__), 'active_listener.pid'),
95
97
  :log_file => File.join(File.dirname(__FILE__), 'active_listener.log'),
@@ -102,11 +104,12 @@ class ActiveListenerTest < Test::Unit::TestCase
102
104
  ActiveListener.stop(
103
105
  :pid_file => File.join(File.dirname(__FILE__), 'active_listener.pid')
104
106
  )
107
+ sleep(1)
105
108
  FileUtils.rm_f(File.join(File.dirname(__FILE__),'sample.txt'))
106
109
  end
107
110
 
108
111
  should "load events from the config file" do
109
- sleep(1)
112
+ sleep(2)
110
113
  assert File.exists?(@sample_file)
111
114
  FileUtils.rm_f(@sample_file)
112
115
  assert !File.exists?(@sample_file)
@@ -114,5 +117,52 @@ class ActiveListenerTest < Test::Unit::TestCase
114
117
  assert File.exists?(@sample_file)
115
118
  end
116
119
 
120
+ should "not duplicate processes" do
121
+ pf = File.new(File.join(File.dirname(__FILE__), 'active_listener.pid'))
122
+ pid = pf.read
123
+ pf.close
124
+ assert(pid_running(pid))
125
+ ActiveListener.autostart(
126
+ :config => File.join(File.dirname(__FILE__), 'active_listener.yml'),
127
+ :pid_file => File.join(File.dirname(__FILE__), 'active_listener.pid'),
128
+ :log_file => File.join(File.dirname(__FILE__), 'active_listener.log'),
129
+ :rake_root => File.join(File.dirname(__FILE__), '..')
130
+ )
131
+ pf = File.new(File.join(File.dirname(__FILE__), 'active_listener.pid'))
132
+ new_pid = pf.read
133
+ pf.close
134
+ assert_equal pid, new_pid
135
+ assert(pid_running(pid))
136
+ end
137
+
138
+ should "be able to be stopped and a new one can be run" do
139
+ pf = File.new(File.join(File.dirname(__FILE__), 'active_listener.pid'))
140
+ pid = pf.read
141
+ pf.close
142
+ assert(pid_running(pid))
143
+ ActiveListener.stop(
144
+ :pid_file => File.join(File.dirname(__FILE__), 'active_listener.pid')
145
+ )
146
+ sleep(1)
147
+ assert(!pid_running(pid))
148
+ ActiveListener.autostart(
149
+ :config => File.join(File.dirname(__FILE__), 'active_listener.yml'),
150
+ :pid_file => File.join(File.dirname(__FILE__), 'active_listener.pid'),
151
+ :log_file => File.join(File.dirname(__FILE__), 'active_listener.log'),
152
+ :rake_root => File.join(File.dirname(__FILE__), '..')
153
+ )
154
+ pf = File.new(File.join(File.dirname(__FILE__), 'active_listener.pid'))
155
+ new_pid = pf.read
156
+ pf.close
157
+ assert_not_equal pid, new_pid
158
+ assert(pid_running(new_pid))
159
+ assert(!pid_running(pid))
160
+ end
161
+ end
162
+
163
+ private
164
+
165
+ def pid_running(pid)
166
+ `ps -p #{pid.to_i.to_s} -o pid=`.size > 0
117
167
  end
118
168
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ngauthier-active-listener
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Gauthier
@@ -23,6 +23,7 @@ extra_rdoc_files: []
23
23
 
24
24
  files:
25
25
  - VERSION.yml
26
+ - README.html
26
27
  - README.markdown
27
28
  - bin/active-listener
28
29
  - lib/activelistener