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.
- data/README.markdown +4 -33
- data/VERSION.yml +2 -2
- data/bin/active-listener +2 -2
- data/lib/active-listener.rb +10 -7
- data/test/active_listener_test.rb +54 -4
- metadata +2 -1
data/README.markdown
CHANGED
@@ -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
|
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
|
|
data/VERSION.yml
CHANGED
data/bin/active-listener
CHANGED
data/lib/active-listener.rb
CHANGED
@@ -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 --
|
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
|
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
|
-
|
65
|
-
|
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 =
|
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
|
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(
|
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.
|
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
|