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,17 @@
|
|
|
1
|
+
# Put your code that runs your task inside the do_work method it will be
|
|
2
|
+
# run automatically in a thread. You have access to all of your rails
|
|
3
|
+
# models. You also get logger and results method inside of this class
|
|
4
|
+
# by default.
|
|
5
|
+
class ErrorWorker < BackgrounDRb::MetaWorker
|
|
6
|
+
set_worker_name :error_worker
|
|
7
|
+
set_no_auto_load(true)
|
|
8
|
+
|
|
9
|
+
def create(args = nil)
|
|
10
|
+
logger.info "creating error worker"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def hello_world(data)
|
|
14
|
+
logger.info "invoking #{worker_name} hello world #{data} #{Time.now}"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Put your code that runs your task inside the do_work method it will be
|
|
2
|
+
# run automatically in a thread. You have access to all of your rails
|
|
3
|
+
# models. You also get logger and results method inside of this class
|
|
4
|
+
# by default.
|
|
5
|
+
|
|
6
|
+
class TimeClient
|
|
7
|
+
def receive_data(p_data)
|
|
8
|
+
worker.get_external_data(p_data)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def post_init
|
|
12
|
+
p "***************** : connection completed"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class FooWorker < BackgrounDRb::MetaWorker
|
|
17
|
+
set_worker_name :foo_worker
|
|
18
|
+
def create(args = nil)
|
|
19
|
+
#register_status("Running")
|
|
20
|
+
add_periodic_timer(10) { foobar }
|
|
21
|
+
external_connection = nil
|
|
22
|
+
connect("localhost",11009,TimeClient) { |conn| external_connection = conn }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def get_external_data(p_data)
|
|
26
|
+
cache[some_key] = p_data
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def foobar
|
|
30
|
+
cache[some_key] = "Time is now : #{Time.now}"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def barbar(data)
|
|
34
|
+
logger.info "invoking babrbar on #{Time.now} #{data}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
class ModelWorker < BackgrounDRb::MetaWorker
|
|
2
|
+
set_worker_name :model_worker
|
|
3
|
+
def create(args = nil)
|
|
4
|
+
#add_periodic_timer(2) { add_new_user }
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def add_new_user
|
|
8
|
+
login,age = "Hemant: #{Time.now}",rand(24)
|
|
9
|
+
logger.info "creating user #{login} with age #{age}"
|
|
10
|
+
User.create(:login => login, :age => age)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# this worker would test thread issues that were discussed before
|
|
2
|
+
require "net/http"
|
|
3
|
+
class RssWorker < BackgrounDRb::MetaWorker
|
|
4
|
+
set_worker_name :rss_worker
|
|
5
|
+
def create(args = nil)
|
|
6
|
+
# this method is called, when worker is loaded for the first time
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# method would fetch supplied urls in a thread
|
|
10
|
+
def fetch_url(url)
|
|
11
|
+
puts "fetching url #{url}"
|
|
12
|
+
thread_pool.defer(:scrap_things,url)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def scrap_things url
|
|
16
|
+
begin
|
|
17
|
+
data = Net::HTTP.get(url,"/")
|
|
18
|
+
File.open("#{RAILS_ROOT}/log/pages.txt","w") do |fl|
|
|
19
|
+
fl.puts(data)
|
|
20
|
+
end
|
|
21
|
+
rescue
|
|
22
|
+
logger.info "Error downloading page"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
class TimeServer
|
|
2
|
+
# the data send by client would be received here
|
|
3
|
+
def receive_data(p_data)
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
# would be called when someone connects to the server for the
|
|
7
|
+
# first time
|
|
8
|
+
def post_init
|
|
9
|
+
add_periodic_timer(2) { say_hello_world }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# would be called when client connection is complete.
|
|
13
|
+
def connection_completed
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def say_hello_world
|
|
17
|
+
send_data("Hello World\n")
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# this worker is going to act like server.
|
|
22
|
+
class ServerWorker < BackgrounDRb::MetaWorker
|
|
23
|
+
set_worker_name :server_worker
|
|
24
|
+
def create(args = nil)
|
|
25
|
+
# start the server when worker starts
|
|
26
|
+
start_server("0.0.0.0",11009,TimeServer) do |client_connection|
|
|
27
|
+
client_connection.say_hello_world
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
data/init.rb
ADDED
data/install.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Install hook code here
|
data/know_issues.org
ADDED
data/lib/backgroundrb.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require "backgroundrb/railtie"
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# class stores connections to BackgrounDRb servers in a cluster manner
|
|
2
|
+
module BackgrounDRb
|
|
3
|
+
class ClusterConnection
|
|
4
|
+
include ClientHelper
|
|
5
|
+
attr_accessor :backend_connections,:config,:cache,:bdrb_servers
|
|
6
|
+
attr_accessor :disconnected_connections
|
|
7
|
+
|
|
8
|
+
# initialize cluster connection
|
|
9
|
+
def initialize
|
|
10
|
+
@bdrb_servers = []
|
|
11
|
+
@backend_connections = []
|
|
12
|
+
@disconnected_connections = {}
|
|
13
|
+
|
|
14
|
+
@last_polled_time = Time.now
|
|
15
|
+
@request_count = 0
|
|
16
|
+
|
|
17
|
+
initialize_memcache if BackgrounDRb::BDRB_CONFIG[:backgroundrb][:result_storage] == 'memcache'
|
|
18
|
+
establish_connections
|
|
19
|
+
@round_robin = (0...@backend_connections.length).to_a
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# initialize memache if client is storing results in memcache
|
|
23
|
+
def initialize_memcache
|
|
24
|
+
require 'memcache'
|
|
25
|
+
memcache_options = {
|
|
26
|
+
:c_threshold => 10_000,
|
|
27
|
+
:compression => true,
|
|
28
|
+
:debug => false,
|
|
29
|
+
:namespace => 'backgroundrb_result_hash',
|
|
30
|
+
:readonly => false,
|
|
31
|
+
:urlencode => false
|
|
32
|
+
}
|
|
33
|
+
@cache = MemCache.new(memcache_options)
|
|
34
|
+
@cache.servers = BackgrounDRb::BDRB_CONFIG[:memcache].split(',')
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# initialize all backend server connections
|
|
38
|
+
def establish_connections
|
|
39
|
+
klass = Struct.new(:ip,:port)
|
|
40
|
+
if t_servers = BackgrounDRb::BDRB_CONFIG[:client]
|
|
41
|
+
connections = t_servers.split(',')
|
|
42
|
+
connections.each do |conn_string|
|
|
43
|
+
ip = conn_string.split(':')[0]
|
|
44
|
+
port = conn_string.split(':')[1].to_i
|
|
45
|
+
@bdrb_servers << klass.new(ip,port)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
@bdrb_servers << klass.new(BackgrounDRb::BDRB_CONFIG[:backgroundrb][:ip],BackgrounDRb::BDRB_CONFIG[:backgroundrb][:port].to_i)
|
|
49
|
+
@bdrb_servers.each_with_index do |connection_info,index|
|
|
50
|
+
next if @backend_connections.detect { |x| x.server_info == "#{connection_info.ip}:#{connection_info.port}" }
|
|
51
|
+
@backend_connections << Connection.new(connection_info.ip,connection_info.port,self)
|
|
52
|
+
end
|
|
53
|
+
end # end of method establish_connections
|
|
54
|
+
|
|
55
|
+
# every 10 request or 10 seconds it will try to reconnect to bdrb servers which were down
|
|
56
|
+
def discover_server_periodically
|
|
57
|
+
@disconnected_connections.each do |key,connection|
|
|
58
|
+
connection.establish_connection
|
|
59
|
+
if connection.connection_status
|
|
60
|
+
@backend_connections << connection
|
|
61
|
+
connection.close_connection
|
|
62
|
+
@disconnected_connections[key] = nil
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
@disconnected_connections.delete_if { |key,value| value.nil? }
|
|
66
|
+
@round_robin = (0...@backend_connections.length).to_a
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Find live connections except those mentioned in array, because they
|
|
70
|
+
# are already dead.
|
|
71
|
+
def find_next_except_these connections
|
|
72
|
+
invalid_connections = @backend_connections.select { |x| connections.include?(x.server_info) }
|
|
73
|
+
@backend_connections.delete_if { |x| connections.include?(x.server_info) }
|
|
74
|
+
@round_robin = (0...@backend_connections.length).to_a
|
|
75
|
+
invalid_connections.each do |x|
|
|
76
|
+
@disconnected_connections[x.server_info] = x
|
|
77
|
+
end
|
|
78
|
+
chosen = @backend_connections.detect { |x| !(connections.include?(x.server_info)) }
|
|
79
|
+
raise NoServerAvailable.new("No BackgrounDRb server is found running") unless chosen
|
|
80
|
+
chosen
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Fina a connection by host name and port
|
|
84
|
+
def find_connection host_info
|
|
85
|
+
conn = @backend_connections.detect { |x| x.server_info == host_info }
|
|
86
|
+
raise NoServerAvailable.new("BackgrounDRb server is not found running on #{host_info}") unless conn
|
|
87
|
+
return conn
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# find the local configured connection
|
|
91
|
+
def find_local
|
|
92
|
+
find_connection("#{BackgrounDRb::BDRB_CONFIG[:backgroundrb][:ip]}:#{BackgrounDRb::BDRB_CONFIG[:backgroundrb][:port]}")
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# return the worker proxy
|
|
96
|
+
def worker(worker_name,worker_key = nil)
|
|
97
|
+
update_stats
|
|
98
|
+
RailsWorkerProxy.new(worker_name,worker_key,self)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Update the stats and discover new nodes if they came up.
|
|
102
|
+
def update_stats
|
|
103
|
+
@request_count += 1
|
|
104
|
+
discover_server_periodically if(time_to_discover? && !@disconnected_connections.empty?)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Check if, we should try to discover new bdrb servers
|
|
108
|
+
def time_to_discover?
|
|
109
|
+
if((@request_count%10 == 0) or (Time.now > (@last_polled_time + 10.seconds)))
|
|
110
|
+
@last_polled_time = Time.now
|
|
111
|
+
return true
|
|
112
|
+
else
|
|
113
|
+
return false
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Send worker information of all currently running workers from all configured bdrb
|
|
118
|
+
# servers
|
|
119
|
+
def all_worker_info
|
|
120
|
+
update_stats
|
|
121
|
+
info_data = {}
|
|
122
|
+
@backend_connections.each do |t_connection|
|
|
123
|
+
info_data[t_connection.server_info] = t_connection.all_worker_info rescue nil
|
|
124
|
+
end
|
|
125
|
+
return info_data
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# one of the backend connections are chosen and worker is started on it
|
|
129
|
+
def new_worker(options = {})
|
|
130
|
+
update_stats
|
|
131
|
+
succeeded = false
|
|
132
|
+
result = nil
|
|
133
|
+
|
|
134
|
+
@backend_connections.each do |connection|
|
|
135
|
+
begin
|
|
136
|
+
result = connection.new_worker(options)
|
|
137
|
+
succeeded = true
|
|
138
|
+
rescue BdrbConnError; end
|
|
139
|
+
end
|
|
140
|
+
raise NoServerAvailable.new("No BackgrounDRb server is found running") unless succeeded
|
|
141
|
+
return options[:worker_key]
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# choose a server in round robin manner.
|
|
145
|
+
def choose_server
|
|
146
|
+
if @round_robin.empty?
|
|
147
|
+
@round_robin = (0...@backend_connections.length).to_a
|
|
148
|
+
end
|
|
149
|
+
if @round_robin.empty? && @backend_connections.empty?
|
|
150
|
+
discover_server_periodically
|
|
151
|
+
raise NoServerAvailable.new("No BackgrounDRb server is found running") if @round_robin.empty? && @backend_connections.empty?
|
|
152
|
+
end
|
|
153
|
+
@backend_connections[@round_robin.shift]
|
|
154
|
+
end
|
|
155
|
+
end # end of ClusterConnection
|
|
156
|
+
end # end of Module BackgrounDRb
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
require 'yaml'
|
|
2
|
+
require 'erb'
|
|
3
|
+
module BackgrounDRb
|
|
4
|
+
class Config
|
|
5
|
+
def self.parse_cmd_options(argv)
|
|
6
|
+
options = { }
|
|
7
|
+
|
|
8
|
+
OptionParser.new do |opts|
|
|
9
|
+
script_name = File.basename($0)
|
|
10
|
+
opts.banner = "Usage: #{$0} [options]"
|
|
11
|
+
opts.separator ""
|
|
12
|
+
opts.on("-e", "--environment=name", String,
|
|
13
|
+
"Specifies the environment to operate under (test/development/production).",
|
|
14
|
+
"Default: development") { |v| options[:environment] = v }
|
|
15
|
+
opts.separator ""
|
|
16
|
+
opts.on("-h", "--help",
|
|
17
|
+
"Show this help message.") { $stderr.puts opts; exit }
|
|
18
|
+
opts.separator ""
|
|
19
|
+
opts.on("-v","--version",
|
|
20
|
+
"Show version.") { $stderr.puts "1.1"; exit }
|
|
21
|
+
end.parse!(argv)
|
|
22
|
+
|
|
23
|
+
ENV["RAILS_ENV"] = options[:environment] if options[:environment]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.read_config(config_file)
|
|
27
|
+
config = YAML.load(ERB.new(IO.read(config_file)).result)
|
|
28
|
+
environment = ENV["RAILS_ENV"] || config[:backgroundrb][:environment] || "development"
|
|
29
|
+
|
|
30
|
+
if respond_to?(:silence_warnings)
|
|
31
|
+
silence_warnings do
|
|
32
|
+
Object.const_set("RAILS_ENV",environment)
|
|
33
|
+
end
|
|
34
|
+
else
|
|
35
|
+
Object.const_set("RAILS_ENV",environment)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
ENV["RAILS_ENV"] = environment
|
|
39
|
+
config
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Exception class for BackgrounDRb connection errors
|
|
2
|
+
module BackgrounDRb
|
|
3
|
+
# raised when connection to a particular server failed
|
|
4
|
+
class BdrbConnError < RuntimeError
|
|
5
|
+
attr_accessor :message
|
|
6
|
+
def initialize(message)
|
|
7
|
+
@message = message
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
# raised when connection to all of the available servers failed
|
|
11
|
+
class NoServerAvailable < RuntimeError
|
|
12
|
+
attr_accessor :message
|
|
13
|
+
def initialize(message)
|
|
14
|
+
@message = message
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# raised, when said task was submitted without a job key, whereas
|
|
19
|
+
# nature of the task requires a job key
|
|
20
|
+
class NoJobKey < RuntimeError; end
|
|
21
|
+
|
|
22
|
+
# raised if worker throws some error
|
|
23
|
+
class RemoteWorkerError < RuntimeError
|
|
24
|
+
attr_accessor :message
|
|
25
|
+
def initialize message
|
|
26
|
+
@message = message
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
module BackgrounDRb
|
|
2
|
+
class Connection
|
|
3
|
+
attr_accessor :server_ip,:server_port,:cluster_conn,:connection_status
|
|
4
|
+
|
|
5
|
+
def initialize ip,port,cluster_conn
|
|
6
|
+
@mutex = Mutex.new
|
|
7
|
+
@server_ip = ip
|
|
8
|
+
@server_port = port
|
|
9
|
+
@cluster_conn = cluster_conn
|
|
10
|
+
@connection_status = true
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def establish_connection
|
|
15
|
+
begin
|
|
16
|
+
timeout(3) do
|
|
17
|
+
@connection = TCPSocket.open(server_ip, server_port)
|
|
18
|
+
@connection.setsockopt(Socket::IPPROTO_TCP,Socket::TCP_NODELAY,1)
|
|
19
|
+
end
|
|
20
|
+
@connection_status = true
|
|
21
|
+
rescue Timeout::Error
|
|
22
|
+
@connection_status = false
|
|
23
|
+
rescue Exception => e
|
|
24
|
+
@connection_status = false
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def write_data data
|
|
29
|
+
begin
|
|
30
|
+
flush_in_loop(data)
|
|
31
|
+
rescue Errno::EAGAIN
|
|
32
|
+
return
|
|
33
|
+
rescue Errno::EPIPE
|
|
34
|
+
establish_connection
|
|
35
|
+
if @connection_status
|
|
36
|
+
flush_in_loop(data)
|
|
37
|
+
else
|
|
38
|
+
@connection_status = false
|
|
39
|
+
raise BackgrounDRb::BdrbConnError.new("Error while writing #{server_info}")
|
|
40
|
+
end
|
|
41
|
+
rescue
|
|
42
|
+
establish_connection
|
|
43
|
+
if @connection_status
|
|
44
|
+
flush_in_loop(data)
|
|
45
|
+
else
|
|
46
|
+
@connection_status = false
|
|
47
|
+
raise BackgrounDRb::BdrbConnError.new("Error while writing #{server_info}")
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def server_info
|
|
53
|
+
"#{server_ip}:#{server_port}"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def flush_in_loop(data)
|
|
57
|
+
t_length = data.length
|
|
58
|
+
loop do
|
|
59
|
+
break if t_length <= 0
|
|
60
|
+
written_length = @connection.write(data)
|
|
61
|
+
raise "Error writing to socket" if written_length <= 0
|
|
62
|
+
result = @connection.flush
|
|
63
|
+
data = data[written_length..-1]
|
|
64
|
+
t_length = data.length
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def dump_object data
|
|
69
|
+
establish_connection
|
|
70
|
+
raise BackgrounDRb::BdrbConnError.new("Error while connecting to the backgroundrb server #{server_info}") unless @connection_status
|
|
71
|
+
|
|
72
|
+
object_dump = Marshal.dump(data)
|
|
73
|
+
dump_length = object_dump.length.to_s
|
|
74
|
+
length_str = dump_length.rjust(9,'0')
|
|
75
|
+
final_data = length_str + object_dump
|
|
76
|
+
@mutex.synchronize { write_data(final_data) }
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def close_connection
|
|
80
|
+
@connection.close
|
|
81
|
+
@connection = nil
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def ask_work p_data
|
|
85
|
+
p_data[:type] = :async_invoke
|
|
86
|
+
dump_object(p_data)
|
|
87
|
+
bdrb_response = nil
|
|
88
|
+
@mutex.synchronize { bdrb_response = read_from_bdrb() }
|
|
89
|
+
close_connection
|
|
90
|
+
bdrb_response
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def new_worker p_data
|
|
94
|
+
p_data[:type] = :start_worker
|
|
95
|
+
dump_object(p_data)
|
|
96
|
+
close_connection
|
|
97
|
+
# RailsWorkerProxy.worker(p_data[:worker],p_data[:worker_key],self)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def worker_info(p_data)
|
|
101
|
+
p_data[:type] = :worker_info
|
|
102
|
+
dump_object(p_data)
|
|
103
|
+
bdrb_response = nil
|
|
104
|
+
@mutex.synchronize { bdrb_response = read_from_bdrb() }
|
|
105
|
+
close_connection
|
|
106
|
+
bdrb_response
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def all_worker_info
|
|
110
|
+
p_data = { }
|
|
111
|
+
p_data[:type] = :all_worker_info
|
|
112
|
+
dump_object(p_data)
|
|
113
|
+
bdrb_response = nil
|
|
114
|
+
@mutex.synchronize { bdrb_response = read_from_bdrb() }
|
|
115
|
+
close_connection
|
|
116
|
+
bdrb_response
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def delete_worker p_data
|
|
120
|
+
p_data[:type] = :delete_worker
|
|
121
|
+
dump_object(p_data)
|
|
122
|
+
close_connection
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def read_object
|
|
126
|
+
begin
|
|
127
|
+
message_length_str = @connection.read(9)
|
|
128
|
+
message_length = message_length_str.to_i
|
|
129
|
+
message_data = @connection.read(message_length)
|
|
130
|
+
return message_data
|
|
131
|
+
rescue
|
|
132
|
+
raise BackgrounDRb::BdrbConnError.new("Not able to connect #{server_info}")
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def gen_key options
|
|
137
|
+
if BDRB_CONFIG[:backgroundrb][:result_storage] == 'memcache'
|
|
138
|
+
key = [options[:worker],options[:worker_key],options[:job_key]].compact.join('_')
|
|
139
|
+
key
|
|
140
|
+
else
|
|
141
|
+
options[:job_key]
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def ask_result(p_data)
|
|
146
|
+
if BDRB_CONFIG[:backgroundrb][:result_storage] == 'memcache'
|
|
147
|
+
return_result_from_memcache(p_data)
|
|
148
|
+
else
|
|
149
|
+
p_data[:type] = :get_result
|
|
150
|
+
dump_object(p_data)
|
|
151
|
+
bdrb_response = nil
|
|
152
|
+
@mutex.synchronize { bdrb_response = read_from_bdrb() }
|
|
153
|
+
close_connection
|
|
154
|
+
bdrb_response ? bdrb_response[:data] : nil
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def read_from_bdrb(timeout = 3)
|
|
159
|
+
begin
|
|
160
|
+
ret_val = select([@connection],nil,nil,timeout)
|
|
161
|
+
return nil unless ret_val
|
|
162
|
+
raw_response = read_object()
|
|
163
|
+
master_response = Marshal.load(raw_response)
|
|
164
|
+
return master_response
|
|
165
|
+
rescue
|
|
166
|
+
return nil
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def send_request(p_data)
|
|
171
|
+
p_data[:type] = :sync_invoke
|
|
172
|
+
dump_object(p_data)
|
|
173
|
+
bdrb_response = nil
|
|
174
|
+
@mutex.synchronize { bdrb_response = read_from_bdrb(nil) }
|
|
175
|
+
close_connection
|
|
176
|
+
bdrb_response
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|