backgroundrb-rails3 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/.autotest +17 -0
- data/ChangeLog +50 -0
- data/Gemfile +11 -0
- data/LICENSE +4 -0
- data/MIT-LICENSE +20 -0
- data/README +22 -0
- data/Rakefile +128 -0
- data/TODO.org +5 -0
- data/app/controller/backgroundrb_status_controller.rb +6 -0
- data/backgroundrb-rails3.gemspec +219 -0
- data/config/backgroundrb.yml +11 -0
- data/doc/Rakefile +5 -0
- data/doc/config.yaml +2 -0
- data/doc/content/advanced/advanced.txt +76 -0
- data/doc/content/advanced/advanced.yaml +4 -0
- data/doc/content/bugs/bugs.txt +20 -0
- data/doc/content/bugs/bugs.yaml +5 -0
- data/doc/content/community/community.txt +36 -0
- data/doc/content/community/community.yaml +5 -0
- data/doc/content/content.txt +168 -0
- data/doc/content/content.yaml +5 -0
- data/doc/content/faq/faq.txt +41 -0
- data/doc/content/faq/faq.yaml +5 -0
- data/doc/content/rails/rails.txt +182 -0
- data/doc/content/rails/rails.yaml +5 -0
- data/doc/content/scheduling/scheduling.txt +166 -0
- data/doc/content/scheduling/scheduling.yaml +5 -0
- data/doc/content/workers/workers.txt +178 -0
- data/doc/content/workers/workers.yaml +5 -0
- data/doc/layouts/default/default.erb +56 -0
- data/doc/layouts/default/default.yaml +4 -0
- data/doc/lib/default.rb +7 -0
- data/doc/output/Assets/BG-Ad-Top.png +0 -0
- data/doc/output/Assets/BG-Body.png +0 -0
- data/doc/output/Assets/BG-Feed.png +0 -0
- data/doc/output/Assets/BG-Menu-Hover.png +0 -0
- data/doc/output/Assets/BG-Menu.png +0 -0
- data/doc/output/Assets/BG-Sidebar-Bottom.png +0 -0
- data/doc/output/Assets/Button-Feed.png +0 -0
- data/doc/output/images/bg-ad-top.png +0 -0
- data/doc/output/images/bg-body.png +0 -0
- data/doc/output/images/bg-feed.gif +0 -0
- data/doc/output/images/bg-footer.jpg +0 -0
- data/doc/output/images/bg-header.jpg +0 -0
- data/doc/output/images/bg-menu-hover.png +0 -0
- data/doc/output/images/bg-menu.png +0 -0
- data/doc/output/images/bg-sidebar-bottom.gif +0 -0
- data/doc/output/images/button-feed.png +0 -0
- data/doc/output/images/icon-comment.png +0 -0
- data/doc/output/images/more_icon.gif +0 -0
- data/doc/output/style.css +299 -0
- data/doc/page_defaults.yaml +13 -0
- data/doc/tasks/default.rake +3 -0
- data/doc/templates/default/default.txt +1 -0
- data/doc/templates/default/default.yaml +4 -0
- data/examples/backgroundrb.yml +25 -0
- data/examples/foo_controller.rb +48 -0
- data/examples/god_worker.rb +7 -0
- data/examples/worker_tests/god_worker_test.rb +8 -0
- data/examples/workers/error_worker.rb +17 -0
- data/examples/workers/foo_worker.rb +38 -0
- data/examples/workers/god_worker.rb +7 -0
- data/examples/workers/model_worker.rb +13 -0
- data/examples/workers/renewal_worker.rb +11 -0
- data/examples/workers/rss_worker.rb +26 -0
- data/examples/workers/server_worker.rb +31 -0
- data/examples/workers/world_worker.rb +12 -0
- data/examples/workers/xmpp_worker.rb +7 -0
- data/init.rb +7 -0
- data/install.rb +1 -0
- data/know_issues.org +5 -0
- data/lib/backgroundrb.rb +1 -0
- data/lib/backgroundrb/bdrb_client_helper.rb +8 -0
- data/lib/backgroundrb/bdrb_cluster_connection.rb +156 -0
- data/lib/backgroundrb/bdrb_config.rb +43 -0
- data/lib/backgroundrb/bdrb_conn_error.rb +29 -0
- data/lib/backgroundrb/bdrb_connection.rb +179 -0
- data/lib/backgroundrb/bdrb_job_queue.rb +79 -0
- data/lib/backgroundrb/bdrb_result.rb +19 -0
- data/lib/backgroundrb/bdrb_start_stop.rb +146 -0
- data/lib/backgroundrb/rails_worker_proxy.rb +181 -0
- data/lib/backgroundrb/railtie.rb +48 -0
- data/lib/generators/backgroundrb/bdrb_migration/USAGE +12 -0
- data/lib/generators/backgroundrb/bdrb_migration/bdrb_migration_generator.rb +15 -0
- data/lib/generators/backgroundrb/bdrb_migration/templates/migration.rb +27 -0
- data/lib/generators/backgroundrb/worker/USAGE +16 -0
- data/lib/generators/backgroundrb/worker/templates/unit_test.rb +12 -0
- data/lib/generators/backgroundrb/worker/templates/worker.rb +7 -0
- data/lib/generators/backgroundrb/worker/worker_generator.rb +14 -0
- data/lib/tasks/backgroundrb_tasks.rake +103 -0
- data/release_notes.org +48 -0
- data/release_points.org +46 -0
- data/script/backgroundrb +52 -0
- data/script/bdrb_test_helper.rb +99 -0
- data/script/load_worker_env.rb +31 -0
- data/script/monitrc +25 -0
- data/server/backgroundrb_server.rb +12 -0
- data/server/lib/bdrb_result_storage.rb +62 -0
- data/server/lib/bdrb_server_helper.rb +24 -0
- data/server/lib/bdrb_thread_pool.rb +127 -0
- data/server/lib/cron_trigger.rb +197 -0
- data/server/lib/invalid_dump_error.rb +4 -0
- data/server/lib/log_worker.rb +25 -0
- data/server/lib/master_proxy.rb +140 -0
- data/server/lib/master_worker.rb +187 -0
- data/server/lib/meta_worker.rb +432 -0
- data/server/lib/trigger.rb +34 -0
- data/test/bdrb_client_test_helper.rb +5 -0
- data/test/bdrb_test_helper.rb +35 -0
- data/test/client/backgroundrb.yml +17 -0
- data/test/client/test_bdrb_client_helper.rb +13 -0
- data/test/client/test_bdrb_cluster_connection.rb +162 -0
- data/test/client/test_bdrb_config.rb +20 -0
- data/test/client/test_bdrb_connection.rb +29 -0
- data/test/client/test_bdrb_job_queue.rb +63 -0
- data/test/client/test_worker_proxy.rb +130 -0
- data/test/server/test_cron_trigger.rb +281 -0
- data/test/server/test_master_proxy.rb +54 -0
- data/test/server/test_master_worker.rb +157 -0
- data/test/server/test_meta_worker.rb +281 -0
- data/test/server/test_result_storage.rb +14 -0
- data/test/socket_mocker.rb +34 -0
- data/test/workers/bar_worker.rb +10 -0
- data/test/workers/foo_worker.rb +10 -0
- data/uninstall.rb +1 -0
- metadata +345 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Model for storing jobs/tasks persisted to the database
|
|
2
|
+
|
|
3
|
+
class BdrbJobQueue < ActiveRecord::Base
|
|
4
|
+
validates_uniqueness_of :job_key,:scope => [:worker_name,:worker_key]
|
|
5
|
+
# find next task from the table
|
|
6
|
+
def self.find_next(worker_name,worker_key = nil)
|
|
7
|
+
returned_job = nil
|
|
8
|
+
ActiveRecord::Base.verify_active_connections!
|
|
9
|
+
transaction do
|
|
10
|
+
unless worker_key
|
|
11
|
+
#use ruby time stamps for time calculations as db might have different times than what is calculated by ruby/rails
|
|
12
|
+
t_job = find(:first,:conditions => [" worker_name = ? AND taken = ? AND scheduled_at <= ? ", worker_name, 0, Time.now.utc ],:lock => true, :order => 'priority desc')
|
|
13
|
+
else
|
|
14
|
+
t_job = find(:first,:conditions => [" worker_name = ? AND taken = ? AND worker_key = ? AND scheduled_at <= ? ", worker_name, 0, worker_key, Time.now.utc ],:lock => true)
|
|
15
|
+
end
|
|
16
|
+
if t_job
|
|
17
|
+
t_job.taken = 1
|
|
18
|
+
t_job.started_at = Time.now.utc
|
|
19
|
+
t_job.save
|
|
20
|
+
returned_job = t_job
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
returned_job
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
#these accessors get around any possible character encoding issues with the database
|
|
27
|
+
def args=(args)
|
|
28
|
+
write_attribute(:args, Base64.encode64(args))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def args
|
|
32
|
+
Base64.decode64(read_attribute(:args))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# release a job and mark it to be unfinished and free.
|
|
36
|
+
# useful, if inside a worker, processing of this job failed and you want it to process later
|
|
37
|
+
def release_job
|
|
38
|
+
ActiveRecord::Base.verify_active_connections!
|
|
39
|
+
self.class.transaction do
|
|
40
|
+
self.taken = 0
|
|
41
|
+
self.started_at = nil
|
|
42
|
+
self.save
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# insert a new job for processing. jobs added will be automatically picked by the appropriate worker
|
|
47
|
+
def self.insert_job(options = { })
|
|
48
|
+
ActiveRecord::Base.verify_active_connections!
|
|
49
|
+
transaction do
|
|
50
|
+
options.merge!(:submitted_at => Time.now.utc,:finished => 0,:taken => 0)
|
|
51
|
+
t_job = new(options)
|
|
52
|
+
t_job.save
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# remove a job from table
|
|
57
|
+
def self.remove_job(options = { })
|
|
58
|
+
ActiveRecord::Base.verify_active_connections!
|
|
59
|
+
transaction do
|
|
60
|
+
t_job_id = find(:first, :conditions => options.merge(:finished => 0,:taken => 0),:lock => true)
|
|
61
|
+
delete(t_job_id)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Mark a job as finished
|
|
66
|
+
def finish!
|
|
67
|
+
ActiveRecord::Base.verify_active_connections!
|
|
68
|
+
self.class.transaction do
|
|
69
|
+
self.finished = 1
|
|
70
|
+
self.finished_at = Time.now.utc
|
|
71
|
+
self.job_key = "finished_#{Time.now.utc.to_i}_#{job_key}"
|
|
72
|
+
self.save
|
|
73
|
+
end
|
|
74
|
+
Thread.current[:persistent_job_id] = nil
|
|
75
|
+
Thread.current[:job_key] = nil
|
|
76
|
+
nil
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module BackgrounDRb
|
|
2
|
+
class Result
|
|
3
|
+
def initialize results
|
|
4
|
+
@results = resuls
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def async_response?
|
|
8
|
+
!(@results[:result] == true)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def sync_response?
|
|
12
|
+
(@results[:result] == true)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def error?
|
|
16
|
+
!(@results[:result_flag] == "ok")
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# see http://refspecs.freestandards.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
|
|
2
|
+
# for LSB-compliancy info
|
|
3
|
+
module BackgrounDRb
|
|
4
|
+
class StartStop
|
|
5
|
+
def start
|
|
6
|
+
if running? # starting an already running process is considered a success
|
|
7
|
+
puts "BackgrounDRb Already Running"
|
|
8
|
+
exit(0)
|
|
9
|
+
elsif dead? # dead, but pid exists
|
|
10
|
+
remove_pidfiles
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# status == 3, not running.
|
|
14
|
+
STDOUT.sync = true
|
|
15
|
+
print("Starting BackgrounDRb .... ")
|
|
16
|
+
start_bdrb
|
|
17
|
+
puts "Success!"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def stop
|
|
21
|
+
pid_files = Dir["#{RAILS_HOME}/tmp/pids/backgroundrb_*.pid"]
|
|
22
|
+
puts "BackgrounDRb Not Running" if pid_files.empty?
|
|
23
|
+
pid_files.each do |x|
|
|
24
|
+
begin
|
|
25
|
+
kill_process(x)
|
|
26
|
+
rescue Errno::ESRCH
|
|
27
|
+
# stopping an already stopped process is considered a success (exit status 0)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
remove_pidfiles
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# returns the correct lsb code for the status:
|
|
34
|
+
# 0 program is running or service is OK
|
|
35
|
+
# 1 program is dead and /var/run pid file exists
|
|
36
|
+
# 3 program is not running
|
|
37
|
+
def status
|
|
38
|
+
@status ||= begin
|
|
39
|
+
if pidfile_exists? and process_running?
|
|
40
|
+
0
|
|
41
|
+
elsif pidfile_exists? # but not process_running
|
|
42
|
+
1
|
|
43
|
+
else
|
|
44
|
+
3
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
return @status
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def pidfile_exists?; File.exists?(PID_FILE); end
|
|
52
|
+
|
|
53
|
+
def process_running?
|
|
54
|
+
begin
|
|
55
|
+
Process.kill(0,self.pid)
|
|
56
|
+
true
|
|
57
|
+
rescue Errno::ESRCH
|
|
58
|
+
false
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def running?;status == 0;end
|
|
63
|
+
# pidfile exists but process isn't running
|
|
64
|
+
|
|
65
|
+
def dead?;status == 1;end
|
|
66
|
+
|
|
67
|
+
def pid
|
|
68
|
+
File.read(PID_FILE).strip.to_i if pidfile_exists?
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def remove_pidfiles
|
|
72
|
+
require 'fileutils'
|
|
73
|
+
FileUtils.rm_r(Dir["#{RAILS_HOME}/tmp/pids/backgroundrb_*.pid"])
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def start_bdrb
|
|
77
|
+
require "rubygems"
|
|
78
|
+
require "yaml"
|
|
79
|
+
require "erb"
|
|
80
|
+
require "logger"
|
|
81
|
+
require "packet"
|
|
82
|
+
require "optparse"
|
|
83
|
+
|
|
84
|
+
require "bdrb_config"
|
|
85
|
+
require RAILS_HOME + "/config/boot"
|
|
86
|
+
require "active_support"
|
|
87
|
+
|
|
88
|
+
BackgrounDRb::Config.parse_cmd_options ARGV
|
|
89
|
+
|
|
90
|
+
require RAILS_HOME + "/config/environment"
|
|
91
|
+
require "bdrb_job_queue"
|
|
92
|
+
require "backgroundrb_server"
|
|
93
|
+
|
|
94
|
+
#proper way to daemonize - double fork to ensure parent can have no interest in the grandchild
|
|
95
|
+
if fork # Parent exits, child continues.
|
|
96
|
+
sleep(5)
|
|
97
|
+
exit(0)
|
|
98
|
+
else
|
|
99
|
+
Process.setsid # Become session leader.
|
|
100
|
+
|
|
101
|
+
op = File.open(PID_FILE, "w")
|
|
102
|
+
op.write(Process.pid().to_s)
|
|
103
|
+
op.close
|
|
104
|
+
|
|
105
|
+
if BDRB_CONFIG[:backgroundrb][:log].nil? or BDRB_CONFIG[:backgroundrb][:log] != 'foreground'
|
|
106
|
+
redirect_io(SERVER_LOGGER)
|
|
107
|
+
end
|
|
108
|
+
$0 = "backgroundrb master"
|
|
109
|
+
BackgrounDRb::MasterProxy.new()
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
#File.open(PID_FILE, "w") {|pidfile| pidfile.write(main_pid)}
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def kill_process(pid_file)
|
|
116
|
+
pid = File.open(pid_file, "r") { |pid_handle| pid_handle.gets.strip.to_i }
|
|
117
|
+
pgid = Process.getpgid(pid)
|
|
118
|
+
Process.kill('-TERM', pgid)
|
|
119
|
+
File.delete(pid_file) if File.exists?(pid_file)
|
|
120
|
+
puts "Stopped BackgrounDRb worker with pid #{pid}"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
# Free file descriptors and
|
|
125
|
+
# point them somewhere sensible
|
|
126
|
+
# STDOUT/STDERR should go to a logfile
|
|
127
|
+
def redirect_io(logfile_name)
|
|
128
|
+
begin; STDIN.reopen "/dev/null"; rescue ::Exception; end
|
|
129
|
+
|
|
130
|
+
if logfile_name
|
|
131
|
+
begin
|
|
132
|
+
STDOUT.reopen logfile_name, "a"
|
|
133
|
+
STDOUT.sync = true
|
|
134
|
+
rescue ::Exception
|
|
135
|
+
begin; STDOUT.reopen "/dev/null"; rescue ::Exception; end
|
|
136
|
+
end
|
|
137
|
+
else
|
|
138
|
+
begin; STDOUT.reopen "/dev/null"; rescue ::Exception; end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
begin; STDERR.reopen STDOUT; rescue ::Exception; end
|
|
142
|
+
STDERR.sync = true
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
end
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
module BackgrounDRb
|
|
2
|
+
# A Worker proxy, which uses +method_missing+ for delegating method calls to the workers
|
|
3
|
+
class RailsWorkerProxy
|
|
4
|
+
attr_accessor :worker_name, :worker_method, :data, :worker_key,:middle_man
|
|
5
|
+
|
|
6
|
+
# create new worker proxy
|
|
7
|
+
def initialize(p_worker_name,p_worker_key = nil,p_middle_man = nil)
|
|
8
|
+
@worker_name = p_worker_name
|
|
9
|
+
@middle_man = p_middle_man
|
|
10
|
+
@worker_key = p_worker_key
|
|
11
|
+
@tried_connections = []
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def method_missing(method_id,*args)
|
|
15
|
+
worker_method = method_id.to_s
|
|
16
|
+
arguments = args.first
|
|
17
|
+
|
|
18
|
+
arg,job_key,host_info,scheduled_at,priority = arguments && arguments.values_at(:arg,:job_key,:host,:scheduled_at, :priority)
|
|
19
|
+
|
|
20
|
+
# allow both arg and args
|
|
21
|
+
arg ||= arguments && arguments[:args]
|
|
22
|
+
|
|
23
|
+
new_schedule = (scheduled_at && scheduled_at.respond_to?(:utc)) ? scheduled_at.utc : Time.now.utc
|
|
24
|
+
|
|
25
|
+
if worker_method =~ /^async_(\w+)/
|
|
26
|
+
method_name = $1
|
|
27
|
+
worker_options = compact(:worker => worker_name,:worker_key => worker_key,
|
|
28
|
+
:worker_method => method_name,:job_key => job_key, :arg => arg)
|
|
29
|
+
run_method(host_info,:ask_work,worker_options)
|
|
30
|
+
elsif worker_method =~ /^enq_(\w+)/i
|
|
31
|
+
raise NoJobKey.new("Must specify a job key with enqueued tasks") if job_key.blank?
|
|
32
|
+
method_name = $1
|
|
33
|
+
marshalled_args = Marshal.dump(arg)
|
|
34
|
+
enqueue_task(compact(:worker_name => worker_name.to_s,:worker_key => worker_key.to_s,
|
|
35
|
+
:worker_method => method_name.to_s,:job_key => job_key.to_s, :priority => priority,
|
|
36
|
+
:args => marshalled_args,:timeout => arguments ? arguments[:timeout] : nil,:scheduled_at => new_schedule))
|
|
37
|
+
elsif worker_method =~ /^deq_(\w+)/i
|
|
38
|
+
raise NoJobKey.new("Must specify a job key to dequeue tasks") if job_key.blank?
|
|
39
|
+
method_name = $1
|
|
40
|
+
dequeue_task(compact(:worker_name => worker_name.to_s,:worker_key => worker_key.to_s,
|
|
41
|
+
:worker_method => method_name.to_s,:job_key => job_key.to_s))
|
|
42
|
+
else
|
|
43
|
+
worker_options = compact(:worker => worker_name,:worker_key => worker_key,
|
|
44
|
+
:worker_method => worker_method,:job_key => job_key,:arg => arg)
|
|
45
|
+
run_method(host_info,:send_request,worker_options)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# enqueue tasks to the worker pool
|
|
50
|
+
def enqueue_task options = {}
|
|
51
|
+
BdrbJobQueue.insert_job(options)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# remove tasks from the worker pool
|
|
55
|
+
def dequeue_task options = {}
|
|
56
|
+
BdrbJobQueue.remove_job(options)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# invoke method on worker
|
|
60
|
+
def run_method host_info,method_name,worker_options = {}
|
|
61
|
+
result = []
|
|
62
|
+
connection = choose_connection(host_info)
|
|
63
|
+
raise NoServerAvailable.new("No BackgrounDRb server is found running") if connection.blank?
|
|
64
|
+
if host_info == :local or host_info.is_a?(String)
|
|
65
|
+
result << invoke_on_connection(connection,method_name,worker_options)
|
|
66
|
+
elsif host_info == :all
|
|
67
|
+
succeeded = false
|
|
68
|
+
begin
|
|
69
|
+
connection.each { |conn| result << invoke_on_connection(conn,method_name,worker_options) }
|
|
70
|
+
succeeded = true
|
|
71
|
+
rescue BdrbConnError; end
|
|
72
|
+
raise NoServerAvailable.new("No BackgrounDRb server is found running") unless succeeded
|
|
73
|
+
else
|
|
74
|
+
@tried_connections = [connection.server_info]
|
|
75
|
+
begin
|
|
76
|
+
result << invoke_on_connection(connection,method_name,worker_options)
|
|
77
|
+
rescue BdrbConnError => e
|
|
78
|
+
connection = middle_man.find_next_except_these(@tried_connections)
|
|
79
|
+
@tried_connections << connection.server_info
|
|
80
|
+
retry
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
#return nil if method_name == :ask_work
|
|
84
|
+
process_result(return_result(result))
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def process_result t_result
|
|
88
|
+
case t_result
|
|
89
|
+
when Hash
|
|
90
|
+
if(t_result[:result] == true && t_result[:type] = :response)
|
|
91
|
+
if(t_result[:result_flag] == "ok")
|
|
92
|
+
return t_result[:data]
|
|
93
|
+
else
|
|
94
|
+
raise RemoteWorkerError.new("Error while executing worker method")
|
|
95
|
+
end
|
|
96
|
+
elsif(t_result[:result_flag] == "ok")
|
|
97
|
+
"ok"
|
|
98
|
+
elsif(t_result[:result_flag] == "error")
|
|
99
|
+
raise RemoteWorkerError.new("Error while executing worker method")
|
|
100
|
+
end
|
|
101
|
+
when Array
|
|
102
|
+
t_result
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# choose a backgroundrb server connection and invoke worker method on it.
|
|
107
|
+
def invoke_on_connection connection,method_name,options = {}
|
|
108
|
+
raise NoServerAvailable.new("No BackgrounDRb is found running") unless connection
|
|
109
|
+
connection.send(method_name,options)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# get results back from the cache. Cache can be in-memory worker cache or memcache
|
|
113
|
+
# based cache
|
|
114
|
+
def ask_result job_key
|
|
115
|
+
options = compact(:worker => worker_name,:worker_key => worker_key,:job_key => job_key)
|
|
116
|
+
if BDRB_CONFIG[:backgroundrb][:result_storage] == 'memcache'
|
|
117
|
+
return_result_from_memcache(options)
|
|
118
|
+
else
|
|
119
|
+
result = middle_man.backend_connections.map { |conn| conn.ask_result(options) }
|
|
120
|
+
return_result(result)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# return runtime information about worker
|
|
125
|
+
def worker_info
|
|
126
|
+
t_connections = middle_man.backend_connections
|
|
127
|
+
result = t_connections.map { |conn| conn.worker_info(compact(:worker => worker_name,:worker_key => worker_key)) }
|
|
128
|
+
return_result(result)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# generate worker key
|
|
132
|
+
def gen_key options
|
|
133
|
+
key = [options[:worker],options[:worker_key],options[:job_key]].compact.join('_')
|
|
134
|
+
key
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# return result from memcache
|
|
138
|
+
def return_result_from_memcache options = {}
|
|
139
|
+
middle_man.cache[gen_key(options)]
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# reset result within memcache for given key
|
|
143
|
+
def reset_memcache_result(job_key,value)
|
|
144
|
+
options = compact(:worker => worker_name,:worker_key => worker_key,\
|
|
145
|
+
:job_key => job_key)
|
|
146
|
+
key = gen_key(options)
|
|
147
|
+
middle_man.cache[key] = value
|
|
148
|
+
value
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def return_result result
|
|
152
|
+
result = Array(result)
|
|
153
|
+
result.size <= 1 ? result[0] : result
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# delete a worker
|
|
157
|
+
def delete
|
|
158
|
+
middle_man.backend_connections.each do |connection|
|
|
159
|
+
connection.delete_worker(compact(:worker => worker_name, :worker_key => worker_key))
|
|
160
|
+
end
|
|
161
|
+
return worker_key
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# choose a worker
|
|
165
|
+
def choose_connection host_info
|
|
166
|
+
case host_info
|
|
167
|
+
when :all; middle_man.backend_connections
|
|
168
|
+
when :local; middle_man.find_local
|
|
169
|
+
when String; middle_man.find_connection(host_info)
|
|
170
|
+
else; middle_man.choose_server
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# helper method to compact a hash and for getting rid of nil parameters
|
|
175
|
+
def compact(options = { })
|
|
176
|
+
options.delete_if { |key,value| value.nil? }
|
|
177
|
+
options
|
|
178
|
+
end
|
|
179
|
+
end # end of RailsWorkerProxy class
|
|
180
|
+
|
|
181
|
+
end # end of BackgrounDRb module
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Backgroundrb
|
|
2
|
+
# FIXME: check if data that we are writing to the socket should end with newline
|
|
3
|
+
require "pathname"
|
|
4
|
+
require "packet"
|
|
5
|
+
require "ostruct"
|
|
6
|
+
|
|
7
|
+
require "rails"
|
|
8
|
+
require "backgroundrb"
|
|
9
|
+
|
|
10
|
+
require "backgroundrb/bdrb_config"
|
|
11
|
+
require "backgroundrb/bdrb_client_helper"
|
|
12
|
+
require "backgroundrb/bdrb_job_queue"
|
|
13
|
+
require "backgroundrb/bdrb_conn_error"
|
|
14
|
+
require "backgroundrb/rails_worker_proxy"
|
|
15
|
+
require "backgroundrb/bdrb_connection"
|
|
16
|
+
require "backgroundrb/bdrb_cluster_connection"
|
|
17
|
+
require "backgroundrb/bdrb_start_stop"
|
|
18
|
+
require "backgroundrb/bdrb_result"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
module BackgrounDRb
|
|
22
|
+
class Railtie < Rails::Railtie
|
|
23
|
+
config.bdrb = ActiveSupport::OrderedOptions.new
|
|
24
|
+
|
|
25
|
+
unless config.bdrb.has_key? :root
|
|
26
|
+
config.bdrb.root = File.expand_path(File.join(__FILE__, '..', '..', '..'))
|
|
27
|
+
end
|
|
28
|
+
BackgrounDRb::BACKGROUNDRB_ROOT = config.bdrb.root
|
|
29
|
+
|
|
30
|
+
config.before_configuration do
|
|
31
|
+
config_file = "#{Rails.root}/config/backgroundrb.yml"
|
|
32
|
+
|
|
33
|
+
if File.exists?(config_file) && !config.bdrb.has_key?(:config)
|
|
34
|
+
config.bdrb.config = BackgrounDRb::Config.read_config(config_file)
|
|
35
|
+
end
|
|
36
|
+
BackgrounDRb::BDRB_CONFIG = config.bdrb.config
|
|
37
|
+
|
|
38
|
+
MiddleMan = BackgrounDRb::ClusterConnection.new if File.exists?(config_file)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
rake_tasks do
|
|
42
|
+
load "tasks/backgroundrb_tasks.rake"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
48
|
+
|