beanstalker 0.0.1 → 0.1.1
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/README +4 -25
- data/Rakefile +4 -2
- data/VERSION +1 -1
- data/glebpom-async_observer.gemspec +56 -0
- data/lib/async_observer/daemonizer_handler.rb +21 -0
- data/lib/async_observer/extend.rb +30 -3
- data/lib/async_observer/queue.rb +16 -9
- data/lib/async_observer/worker.rb +78 -118
- metadata +43 -12
- data/bin/worker +0 -70
- data/lib/async_observer/daemonize.rb +0 -35
- data/lib/async_observer/util.rb +0 -31
data/README
CHANGED
@@ -1,27 +1,6 @@
|
|
1
|
-
This is
|
2
|
-
Beanstalk.
|
1
|
+
This is Beanstalker -- a Rails gem that provides deep integration with
|
2
|
+
Beanstalk. (forked from async_observer)
|
3
3
|
|
4
|
-
|
4
|
+
This version is rewritten using daemonizer.
|
5
5
|
|
6
|
-
|
7
|
-
http://xph.us/software/beanstalkd/.
|
8
|
-
|
9
|
-
|
10
|
-
Worker Options:
|
11
|
-
-d : daemonize
|
12
|
-
--pid [path to pidfile] : drop a pid file to a path
|
13
|
-
-e [test,production,development] : set the rails environment
|
14
|
-
|
15
|
-
Example Usage:
|
16
|
-
|
17
|
-
start 3 workers
|
18
|
-
./vendor/plugins/async_observer/bin/worker -d --pid log/worker1.pid -e production
|
19
|
-
./vendor/plugins/async_observer/bin/worker -d --pid log/worker2.pid -e production
|
20
|
-
./vendor/plugins/async_observer/bin/worker -d --pid log/worker3.pid -e production
|
21
|
-
|
22
|
-
kill one
|
23
|
-
kill -s INT `cat log/worker1.pid`
|
24
|
-
|
25
|
-
Remember kill a worker will cause it to go into a shutdown phase.
|
26
|
-
Run the above again to kill immediately, but remember all jobs in
|
27
|
-
the workers queue is lost at that point...
|
6
|
+
Documentation coming soon...
|
data/Rakefile
CHANGED
@@ -6,12 +6,14 @@ begin
|
|
6
6
|
Jeweler::Tasks.new do |gem|
|
7
7
|
gem.name = "beanstalker"
|
8
8
|
gem.summary = %Q{Beanstalker provides deep integration with Beanstalk. Fork from http://github.com/kristjan/async_observer}
|
9
|
-
gem.description = %Q{Beanstalker
|
9
|
+
gem.description = %Q{Beanstalker is a tool for executing long tasks in background in our rails application.}
|
10
10
|
gem.email = "glebpom@gmail.com"
|
11
11
|
gem.homepage = "http://github.com/glebpom/beanstalker"
|
12
12
|
gem.authors = ["Gleb Pomykalov"]
|
13
13
|
# gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
14
|
-
gem.add_dependency "daemonizer"
|
14
|
+
gem.add_dependency "daemonizer", "~>0.2.0"
|
15
|
+
gem.add_dependency "beanstalk-client"
|
16
|
+
gem.add_dependency "rails", ">= 2.2.0"
|
15
17
|
end
|
16
18
|
Jeweler::GemcutterTasks.new
|
17
19
|
rescue LoadError
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.1.1
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{glebpom-async_observer}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Gleb Pomykalov"]
|
12
|
+
s.date = %q{2010-07-14}
|
13
|
+
s.description = %q{async_observer provides deep integration with Beanstalk. Fork from http://github.com/kristjan/async_observer}
|
14
|
+
s.email = %q{glebpom@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".gitignore",
|
20
|
+
"COPYING",
|
21
|
+
"README",
|
22
|
+
"Rakefile",
|
23
|
+
"VERSION",
|
24
|
+
"glebpom-async_observer.gemspec",
|
25
|
+
"init.rb",
|
26
|
+
"lib/async_observer/daemonizer_handler.rb",
|
27
|
+
"lib/async_observer/extend.rb",
|
28
|
+
"lib/async_observer/queue.rb",
|
29
|
+
"lib/async_observer/worker.rb"
|
30
|
+
]
|
31
|
+
s.homepage = %q{http://github.com/glebpom/async_observer}
|
32
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
33
|
+
s.require_paths = ["lib"]
|
34
|
+
s.rubygems_version = %q{1.3.7}
|
35
|
+
s.summary = %q{async_observer provides deep integration with Beanstalk. Fork from http://github.com/kristjan/async_observer}
|
36
|
+
|
37
|
+
if s.respond_to? :specification_version then
|
38
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
39
|
+
s.specification_version = 3
|
40
|
+
|
41
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
42
|
+
s.add_runtime_dependency(%q<daemonizer>, ["~> 0.2.0"])
|
43
|
+
s.add_runtime_dependency(%q<beanstalk-client>, [">= 0"])
|
44
|
+
s.add_runtime_dependency(%q<rails>, [">= 2.2.0"])
|
45
|
+
else
|
46
|
+
s.add_dependency(%q<daemonizer>, ["~> 0.2.0"])
|
47
|
+
s.add_dependency(%q<beanstalk-client>, [">= 0"])
|
48
|
+
s.add_dependency(%q<rails>, [">= 2.2.0"])
|
49
|
+
end
|
50
|
+
else
|
51
|
+
s.add_dependency(%q<daemonizer>, ["~> 0.2.0"])
|
52
|
+
s.add_dependency(%q<beanstalk-client>, [">= 0"])
|
53
|
+
s.add_dependency(%q<rails>, [">= 2.2.0"])
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module AsyncObserver
|
2
|
+
class DaemonizerHandler < Daemonizer::Handler
|
3
|
+
def prepare(block)
|
4
|
+
logger.info "Loading Rails"
|
5
|
+
require File.join(Daemonizer.root, '/config/environment')
|
6
|
+
require 'async_observer/worker'
|
7
|
+
logger.info "Rails loaded"
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def start
|
12
|
+
logger.info "Starting cycle"
|
13
|
+
Worker.new(binding,
|
14
|
+
:tube => option(:tube),
|
15
|
+
:servers => option(:servers),
|
16
|
+
:worker_id => worker_id,
|
17
|
+
:workers_count => workers_count).run
|
18
|
+
logger.info "Ending cycle"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -29,12 +29,39 @@ CLASSES_TO_EXTEND = [
|
|
29
29
|
]
|
30
30
|
|
31
31
|
module AsyncObserver::Extensions
|
32
|
+
def self.included(receiver)
|
33
|
+
@@methods_async_options = {}
|
34
|
+
receiver.extend(ClassMethods)
|
35
|
+
end
|
36
|
+
|
37
|
+
module ClassMethods
|
38
|
+
def async_method(method, options = {})
|
39
|
+
methods_async_options = class_variable_get(:@@methods_async_options)
|
40
|
+
if options
|
41
|
+
class_variable_set(:@@methods_async_options, methods_async_options.merge(method.to_sym => options))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def interpolate_async_options(options, object)
|
47
|
+
result = {}
|
48
|
+
options.each do |k,v|
|
49
|
+
result[k] = if v.is_a?(Proc)
|
50
|
+
v.call(object)
|
51
|
+
else
|
52
|
+
v
|
53
|
+
end
|
54
|
+
end
|
55
|
+
result
|
56
|
+
end
|
57
|
+
|
32
58
|
def async_send(selector, *args)
|
33
|
-
async_send_opts(selector, {}, *args)
|
59
|
+
async_send_opts(selector, @@methods_async_options[selector.to_sym] || {}, *args)
|
34
60
|
end
|
35
61
|
|
36
62
|
def async_send_opts(selector, opts, *args)
|
37
|
-
|
63
|
+
interpolated_options = interpolate_async_options(opts, self)
|
64
|
+
AsyncObserver::Queue.put_call!(self, selector, interpolated_options, args)
|
38
65
|
end
|
39
66
|
end
|
40
67
|
|
@@ -73,7 +100,7 @@ class Range
|
|
73
100
|
fanout_opts = opts.merge(:fuzz => opts.fetch(:fanout_fuzz,
|
74
101
|
DEFAULT_FANOUT_FUZZ))
|
75
102
|
fanout_opts[:pri] = opts[:fanout_pri] || opts[:pri]
|
76
|
-
fanout_opts = fanout_opts.
|
103
|
+
fanout_opts = fanout_opts.reject{ |k,v| v.nil? }
|
77
104
|
split_to(fanout_degree) do |subrange|
|
78
105
|
subrange.async_send_opts(:async_each_opts, fanout_opts, rcv, selector,
|
79
106
|
opts, *extra)
|
data/lib/async_observer/queue.rb
CHANGED
@@ -29,7 +29,7 @@ class << AsyncObserver::Queue
|
|
29
29
|
DEFAULT_TTR = 120
|
30
30
|
DEFAULT_TUBE = 'default'
|
31
31
|
|
32
|
-
attr_accessor :queue, :
|
32
|
+
attr_accessor :queue, :after_put
|
33
33
|
|
34
34
|
# This is a fake worker instance for running jobs synchronously.
|
35
35
|
def sync_worker()
|
@@ -48,7 +48,7 @@ class << AsyncObserver::Queue
|
|
48
48
|
|
49
49
|
def put!(obj, pri=DEFAULT_PRI, delay=DEFAULT_DELAY, ttr=DEFAULT_TTR,
|
50
50
|
tube=DEFAULT_TUBE)
|
51
|
-
return sync_run(obj) if
|
51
|
+
return sync_run(obj) if pri == :direct || !queue
|
52
52
|
queue.connect()
|
53
53
|
queue.use(tube)
|
54
54
|
info = [queue.yput(obj, pri, delay, ttr), queue.last_server]
|
@@ -64,14 +64,21 @@ class << AsyncObserver::Queue
|
|
64
64
|
fuzz = opts.fetch(:fuzz, DEFAULT_FUZZ)
|
65
65
|
delay = opts.fetch(:delay, DEFAULT_DELAY)
|
66
66
|
ttr = opts.fetch(:ttr, DEFAULT_TTR)
|
67
|
-
tube = opts.fetch(:tube,
|
67
|
+
tube = opts.fetch(:tube, DEFAULT_TUBE)
|
68
68
|
worker_opts = opts.reject{|k,v| SUBMIT_OPTS.include?(k)}
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
69
|
+
interpolator = opts.fetch(:interpolator, nil)
|
70
|
+
|
71
|
+
pri = pri + rand(fuzz + 1) if pri != :direct
|
72
|
+
|
73
|
+
if interpolator
|
74
|
+
code = packed = interpolator
|
75
|
+
else
|
76
|
+
code = gen(obj, sel, args)
|
77
|
+
packed = pkg(code, worker_opts)
|
78
|
+
end
|
79
|
+
|
80
|
+
RAILS_DEFAULT_LOGGER.info("put #{pri} #{code} to #{tube}")
|
81
|
+
put!(packed, pri, delay, ttr, tube)
|
75
82
|
end
|
76
83
|
|
77
84
|
def pkg(code, opts)
|
@@ -15,20 +15,11 @@
|
|
15
15
|
# You should have received a copy of the GNU General Public License
|
16
16
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
17
|
|
18
|
-
|
19
|
-
begin
|
20
|
-
require 'mysql'
|
21
|
-
rescue LoadError
|
22
|
-
# Ignore case where we don't have mysql
|
23
|
-
end
|
24
18
|
require 'async_observer/queue'
|
25
|
-
require 'async_observer/util'
|
26
19
|
|
27
20
|
module AsyncObserver; end
|
28
21
|
|
29
22
|
class AsyncObserver::Worker
|
30
|
-
extend AsyncObserver::Util
|
31
|
-
include AsyncObserver::Util
|
32
23
|
|
33
24
|
SLEEP_TIME = 60 if !defined?(SLEEP_TIME) # rails loads this file twice
|
34
25
|
|
@@ -55,58 +46,50 @@ class AsyncObserver::Worker
|
|
55
46
|
end
|
56
47
|
|
57
48
|
def run_before_reserve
|
58
|
-
before_reserves.each {|b| b.call
|
49
|
+
before_reserves.each {|b| b.call}
|
59
50
|
end
|
60
51
|
end
|
52
|
+
|
53
|
+
def logger
|
54
|
+
$logger or RAILS_DEFAULT_LOGGER
|
55
|
+
end
|
61
56
|
|
62
|
-
def initialize(top_binding)
|
57
|
+
def initialize(top_binding, options = {})
|
63
58
|
@top_binding = top_binding
|
64
59
|
@stop = false
|
60
|
+
@options = options
|
61
|
+
if @options && @options[:servers]
|
62
|
+
AsyncObserver::Queue.queue = Beanstalk::Pool.new(@options[:servers])
|
63
|
+
end
|
65
64
|
end
|
66
65
|
|
67
|
-
def main_loop
|
66
|
+
def main_loop
|
68
67
|
trap('TERM') { @stop = true }
|
69
68
|
loop do
|
70
69
|
break if @stop
|
71
|
-
safe_dispatch(get_job
|
70
|
+
safe_dispatch(get_job)
|
72
71
|
end
|
73
72
|
end
|
74
73
|
|
75
|
-
def startup
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
RAILS_DEFAULT_LOGGER.info "app version is #{appver}"
|
80
|
-
mark_db_socket_close_on_exec()
|
81
|
-
if AsyncObserver::Queue.queue.nil?
|
82
|
-
RAILS_DEFAULT_LOGGER.info 'no queue has been configured'
|
83
|
-
exit(1)
|
84
|
-
end
|
85
|
-
AsyncObserver::Queue.queue.watch(appver) if appver
|
86
|
-
end
|
74
|
+
def startup
|
75
|
+
tube = @options[:tube] || "default"
|
76
|
+
logger.info "Using tube #{tube}"
|
77
|
+
AsyncObserver::Queue.queue.watch(tube)
|
87
78
|
flush_logger
|
88
79
|
end
|
89
80
|
|
90
|
-
|
91
|
-
|
92
|
-
ActiveRecord::Base.active_connections.each(&:set_close_on_exec)
|
93
|
-
rescue NoMethodError
|
94
|
-
end
|
95
|
-
|
96
|
-
def shutdown()
|
97
|
-
log_bracketed('worker-shutdown') do
|
98
|
-
do_all_work()
|
99
|
-
end
|
81
|
+
def shutdown
|
82
|
+
do_all_work
|
100
83
|
end
|
101
84
|
|
102
|
-
def run
|
103
|
-
startup
|
104
|
-
main_loop
|
85
|
+
def run
|
86
|
+
startup
|
87
|
+
main_loop
|
105
88
|
rescue Interrupt
|
106
|
-
shutdown
|
89
|
+
shutdown
|
107
90
|
end
|
108
91
|
|
109
|
-
def q_hint
|
92
|
+
def q_hint
|
110
93
|
@q_hint || AsyncObserver::Queue.queue
|
111
94
|
end
|
112
95
|
|
@@ -114,9 +97,9 @@ class AsyncObserver::Worker
|
|
114
97
|
# if the connection returns a job right away, it probably has more available.
|
115
98
|
# But if it takes time, then it's probably empty. So reuse the same
|
116
99
|
# connection as long as it stays fast. Otherwise, have no preference.
|
117
|
-
def reserve_and_set_hint
|
100
|
+
def reserve_and_set_hint
|
118
101
|
t1 = Time.now.utc
|
119
|
-
return job = q_hint
|
102
|
+
return job = q_hint.reserve
|
120
103
|
ensure
|
121
104
|
t2 = Time.now.utc
|
122
105
|
@q_hint = if brief?(t1, t2) and job then job.conn else nil end
|
@@ -126,29 +109,27 @@ class AsyncObserver::Worker
|
|
126
109
|
((t2 - t1) * 100).to_i.abs < 10
|
127
110
|
end
|
128
111
|
|
129
|
-
def get_job
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
sleep(SLEEP_TIME)
|
151
|
-
end
|
112
|
+
def get_job
|
113
|
+
loop do
|
114
|
+
begin
|
115
|
+
AsyncObserver::Queue.queue.connect
|
116
|
+
self.class.run_before_reserve
|
117
|
+
return reserve_and_set_hint
|
118
|
+
rescue Interrupt => ex
|
119
|
+
raise ex
|
120
|
+
rescue SignalException => ex
|
121
|
+
raise ex
|
122
|
+
rescue Beanstalk::DeadlineSoonError
|
123
|
+
# Do nothing; immediately try again, giving the user a chance to
|
124
|
+
# clean up in the before_reserve hook.
|
125
|
+
logger.info 'Job deadline soon; you should clean up.'
|
126
|
+
rescue Exception => ex
|
127
|
+
@q_hint = nil # in case there's something wrong with this conn
|
128
|
+
logger.info(
|
129
|
+
"#{ex.class}: #{ex}\n" + ex.backtrace.join("\n"))
|
130
|
+
logger.info 'something is wrong. We failed to get a job.'
|
131
|
+
logger.info "sleeping for #{SLEEP_TIME}s..."
|
132
|
+
sleep(SLEEP_TIME)
|
152
133
|
end
|
153
134
|
end
|
154
135
|
end
|
@@ -160,30 +141,26 @@ class AsyncObserver::Worker
|
|
160
141
|
end
|
161
142
|
|
162
143
|
def safe_dispatch(job)
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
begin
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
handle_error(job, ex)
|
177
|
-
ensure
|
178
|
-
flush_logger
|
179
|
-
end
|
144
|
+
logger.info "got #{job.inspect}:\n" + job.body
|
145
|
+
job.stats.each do |k,v|
|
146
|
+
logger.info "#{k}=#{v}"
|
147
|
+
end
|
148
|
+
begin
|
149
|
+
return dispatch(job)
|
150
|
+
rescue Interrupt => ex
|
151
|
+
begin job.release rescue :ok end
|
152
|
+
raise ex
|
153
|
+
rescue Exception => ex
|
154
|
+
handle_error(job, ex)
|
155
|
+
ensure
|
156
|
+
flush_logger
|
180
157
|
end
|
181
158
|
end
|
182
159
|
|
183
160
|
def flush_logger
|
184
|
-
if defined?(
|
185
|
-
|
186
|
-
|
161
|
+
if defined?(logger) &&
|
162
|
+
logger.respond_to?(:flush)
|
163
|
+
logger.flush
|
187
164
|
end
|
188
165
|
end
|
189
166
|
|
@@ -196,25 +173,30 @@ class AsyncObserver::Worker
|
|
196
173
|
end
|
197
174
|
|
198
175
|
def self.default_handle_error(job, ex)
|
199
|
-
|
200
|
-
|
201
|
-
job.
|
176
|
+
logger.info "Job failed: #{job.server}/#{job.id}"
|
177
|
+
logger.info("#{ex.class}: #{ex}\n" + ex.backtrace.join("\n"))
|
178
|
+
if job.stats['releases'] > 10
|
179
|
+
job.bury
|
180
|
+
logger.info "BURY job due to many releases"
|
181
|
+
else
|
182
|
+
job.decay
|
183
|
+
end
|
202
184
|
rescue Beanstalk::UnexpectedResponse
|
203
185
|
end
|
204
186
|
|
205
187
|
def run_ao_job(job)
|
206
|
-
|
188
|
+
logger.info 'running as async observer job'
|
207
189
|
f = self.class.before_filter
|
208
190
|
f.call(job) if f
|
209
191
|
job.delete if job.ybody[:delete_first]
|
210
192
|
run_code(job)
|
211
|
-
job.delete
|
193
|
+
job.delete unless job.ybody[:delete_first]
|
212
194
|
rescue ActiveRecord::RecordNotFound => ex
|
213
195
|
unless job.ybody[:delete_first]
|
214
196
|
if job.age > 60
|
215
|
-
job.delete
|
197
|
+
job.delete # it's old; this error is most likely permanent
|
216
198
|
else
|
217
|
-
job.decay
|
199
|
+
job.decay # it could be replication delay so retry quietly
|
218
200
|
end
|
219
201
|
end
|
220
202
|
end
|
@@ -228,36 +210,14 @@ class AsyncObserver::Worker
|
|
228
210
|
end
|
229
211
|
|
230
212
|
def run_other(job)
|
231
|
-
|
213
|
+
logger.info 'trying custom handler'
|
232
214
|
self.class.handle.call(job)
|
233
215
|
end
|
234
216
|
|
235
|
-
def do_all_work
|
236
|
-
|
217
|
+
def do_all_work
|
218
|
+
logger.info 'finishing all running jobs. interrupt again to kill them.'
|
237
219
|
f = self.class.finish
|
238
|
-
f.call
|
220
|
+
f.call if f
|
239
221
|
end
|
240
222
|
end
|
241
223
|
|
242
|
-
class ActiveRecord::ConnectionAdapters::MysqlAdapter < ActiveRecord::ConnectionAdapters::AbstractAdapter
|
243
|
-
def set_close_on_exec()
|
244
|
-
@connection.set_close_on_exec()
|
245
|
-
end
|
246
|
-
end
|
247
|
-
|
248
|
-
class Mysql
|
249
|
-
def set_close_on_exec()
|
250
|
-
if @net
|
251
|
-
@net.set_close_on_exec()
|
252
|
-
else
|
253
|
-
# we are in the c mysql binding
|
254
|
-
RAILS_DEFAULT_LOGGER.info "Warning: we are using the C mysql binding, can't set close-on-exec"
|
255
|
-
end
|
256
|
-
end
|
257
|
-
end
|
258
|
-
|
259
|
-
class Mysql::Net
|
260
|
-
def set_close_on_exec()
|
261
|
-
@sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
262
|
-
end
|
263
|
-
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: beanstalker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
- 0
|
9
8
|
- 1
|
10
|
-
|
9
|
+
- 1
|
10
|
+
version: 0.1.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Gleb Pomykalov
|
@@ -15,13 +15,29 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-07-
|
19
|
-
default_executable:
|
18
|
+
date: 2010-07-14 00:00:00 +04:00
|
19
|
+
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
22
|
name: daemonizer
|
23
23
|
prerelease: false
|
24
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 23
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 2
|
33
|
+
- 0
|
34
|
+
version: 0.2.0
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: beanstalk-client
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
25
41
|
none: false
|
26
42
|
requirements:
|
27
43
|
- - ">="
|
@@ -31,11 +47,27 @@ dependencies:
|
|
31
47
|
- 0
|
32
48
|
version: "0"
|
33
49
|
type: :runtime
|
34
|
-
version_requirements: *
|
35
|
-
|
50
|
+
version_requirements: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
name: rails
|
53
|
+
prerelease: false
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 7
|
60
|
+
segments:
|
61
|
+
- 2
|
62
|
+
- 2
|
63
|
+
- 0
|
64
|
+
version: 2.2.0
|
65
|
+
type: :runtime
|
66
|
+
version_requirements: *id003
|
67
|
+
description: Beanstalker is a tool for executing long tasks in background in our rails application.
|
36
68
|
email: glebpom@gmail.com
|
37
|
-
executables:
|
38
|
-
|
69
|
+
executables: []
|
70
|
+
|
39
71
|
extensions: []
|
40
72
|
|
41
73
|
extra_rdoc_files:
|
@@ -46,12 +78,11 @@ files:
|
|
46
78
|
- README
|
47
79
|
- Rakefile
|
48
80
|
- VERSION
|
49
|
-
-
|
81
|
+
- glebpom-async_observer.gemspec
|
50
82
|
- init.rb
|
51
|
-
- lib/async_observer/
|
83
|
+
- lib/async_observer/daemonizer_handler.rb
|
52
84
|
- lib/async_observer/extend.rb
|
53
85
|
- lib/async_observer/queue.rb
|
54
|
-
- lib/async_observer/util.rb
|
55
86
|
- lib/async_observer/worker.rb
|
56
87
|
has_rdoc: true
|
57
88
|
homepage: http://github.com/glebpom/beanstalker
|
data/bin/worker
DELETED
@@ -1,70 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# async-observer - Rails plugin for asynchronous job execution
|
3
|
-
|
4
|
-
# Copyright (C) 2007 Philotic Inc.
|
5
|
-
|
6
|
-
# This program is free software: you can redistribute it and/or modify
|
7
|
-
# it under the terms of the GNU General Public License as published by
|
8
|
-
# the Free Software Foundation, either version 3 of the License, or
|
9
|
-
# (at your option) any later version.
|
10
|
-
|
11
|
-
# This program is distributed in the hope that it will be useful,
|
12
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
-
# GNU General Public License for more details.
|
15
|
-
|
16
|
-
# You should have received a copy of the GNU General Public License
|
17
|
-
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
18
|
-
|
19
|
-
|
20
|
-
# Use the same pointer (and therefore same buffer) for stdout and stderr.
|
21
|
-
$VERBOSE = nil; STDERR = $stderr = STDOUT = $stdout; $VERBOSE = false
|
22
|
-
|
23
|
-
require 'time'
|
24
|
-
|
25
|
-
def load_rails_and_run
|
26
|
-
# Rails initialization.
|
27
|
-
# We do this here instead of using script/runner because script/runner
|
28
|
-
# breaks __FILE__, which we use below.
|
29
|
-
begin
|
30
|
-
puts "#!load-rails!begin!#{Time.now.utc.xmlschema(6)}"
|
31
|
-
require File.expand_path(File.dirname(__FILE__) + '/../../../../config/boot')
|
32
|
-
puts "RAILS_ROOT=#{RAILS_ROOT.inspect}"
|
33
|
-
require RAILS_ROOT + '/config/environment'
|
34
|
-
ensure
|
35
|
-
puts "#!load-rails!end!#{Time.now.utc.xmlschema(6)}"
|
36
|
-
end
|
37
|
-
require 'async_observer/worker'
|
38
|
-
AsyncObserver::Worker.new(binding).run()
|
39
|
-
end
|
40
|
-
|
41
|
-
# set environment
|
42
|
-
if ARGV.include?('-e') # check rails env
|
43
|
-
env=nil
|
44
|
-
ARGV.each_with_index{|arg,i| env = ARGV[i+1] if arg == '-e' }
|
45
|
-
RAILS_ENV=env unless env.nil?
|
46
|
-
end
|
47
|
-
|
48
|
-
if ARGV.include?('-d')
|
49
|
-
pidpath = 'log/worker.pid'
|
50
|
-
if ARGV.include?('--pid') # look up the pid path
|
51
|
-
ARGV.each_with_index{|arg,i| pidpath = ARGV[i+1] if arg == '--pid' }
|
52
|
-
STDERR.puts "Missing pid file path!" and exit(1) if pidpath.nil?
|
53
|
-
end
|
54
|
-
unless File.writable?(File.dirname(pidpath))
|
55
|
-
STDERR.puts "#{pidpath} not writable!"
|
56
|
-
exit(1)
|
57
|
-
end
|
58
|
-
|
59
|
-
if File.exist?(pidpath)
|
60
|
-
STDERR.puts "#{pidpath} exits! Make sure the worker isn't still running and try again after rm #{pidpath}"
|
61
|
-
exit(1)
|
62
|
-
end
|
63
|
-
|
64
|
-
require File.dirname(__FILE__) + '/../lib/async_observer/daemonize'
|
65
|
-
AsyncObserver::Daemonize.detach(pidpath) do
|
66
|
-
load_rails_and_run
|
67
|
-
end
|
68
|
-
else
|
69
|
-
load_rails_and_run
|
70
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
# async-observer - Rails plugin for asynchronous job execution
|
2
|
-
# Copyright (C) 2009 Todd A. Fisher.
|
3
|
-
|
4
|
-
# This program is free software: you can redistribute it and/or modify
|
5
|
-
# it under the terms of the GNU General Public License as published by
|
6
|
-
# the Free Software Foundation, either version 3 of the License, or
|
7
|
-
# (at your option) any later version.
|
8
|
-
|
9
|
-
# This program is distributed in the hope that it will be useful,
|
10
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
-
# GNU General Public License for more details.
|
13
|
-
|
14
|
-
# You should have received a copy of the GNU General Public License
|
15
|
-
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
-
module AsyncObserver; end
|
17
|
-
|
18
|
-
class AsyncObserver::Daemonize
|
19
|
-
def self.detach(pidfile='log/worker.pid',&block)
|
20
|
-
# daemonize, create a pipe to send status to the parent process, after the child has successfully started or failed
|
21
|
-
fork do
|
22
|
-
Process.setsid
|
23
|
-
fork do
|
24
|
-
Process.setsid
|
25
|
-
File.open(pidfile, 'wb') {|f| f << Process.pid}
|
26
|
-
at_exit { File.unlink(pidfile) }
|
27
|
-
File.umask 0000
|
28
|
-
STDIN.reopen "/dev/null"
|
29
|
-
STDOUT.reopen "/dev/null", "a"
|
30
|
-
STDERR.reopen STDOUT
|
31
|
-
block.call
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
data/lib/async_observer/util.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
# async-observer - Rails plugin for asynchronous job execution
|
2
|
-
|
3
|
-
# Copyright (C) 2007 Philotic Inc.
|
4
|
-
|
5
|
-
# This program is free software: you can redistribute it and/or modify
|
6
|
-
# it under the terms of the GNU General Public License as published by
|
7
|
-
# the Free Software Foundation, either version 3 of the License, or
|
8
|
-
# (at your option) any later version.
|
9
|
-
|
10
|
-
# This program is distributed in the hope that it will be useful,
|
11
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
-
# GNU General Public License for more details.
|
14
|
-
|
15
|
-
# You should have received a copy of the GNU General Public License
|
16
|
-
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
-
|
18
|
-
|
19
|
-
require 'open3'
|
20
|
-
|
21
|
-
module AsyncObserver; end
|
22
|
-
module AsyncObserver::Util
|
23
|
-
def log_bracketed(name)
|
24
|
-
begin
|
25
|
-
RAILS_DEFAULT_LOGGER.info "#!#{name}!begin!#{Time.now.utc.xmlschema(6)}"
|
26
|
-
yield()
|
27
|
-
ensure
|
28
|
-
RAILS_DEFAULT_LOGGER.info "#!#{name}!end!#{Time.now.utc.xmlschema(6)}"
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|