josip-backgroundrb_merb 1.0.3
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/LICENSE +4 -0
- data/README +45 -0
- data/Rakefile +44 -0
- data/TODO +8 -0
- data/config/backgroundrb.yml +11 -0
- data/generators/worker/USAGE +16 -0
- data/generators/worker/templates/app/workers/%worker_file_name%_worker.rb +7 -0
- data/generators/worker/templates/spec/workers/%worker_file_name%_spec.rb +9 -0
- data/generators/worker/worker_generator.rb +36 -0
- data/lib/backgroundrb_merb.rb +19 -0
- data/lib/backgroundrb_merb/bdrb_config.rb +47 -0
- data/lib/backgroundrb_merb/bdrb_conn_error.rb +9 -0
- data/lib/backgroundrb_merb/merb_worker_proxy.rb +57 -0
- data/lib/backgroundrb_merb/merbtasks.rb +91 -0
- data/lib/backgroundrb_merb/worker_proxy.rb +174 -0
- data/server/backgroundrb_server.rb +7 -0
- data/server/lib/cron_trigger.rb +195 -0
- data/server/lib/invalid_dump_error.rb +4 -0
- data/server/lib/log_worker.rb +25 -0
- data/server/lib/master_worker.rb +301 -0
- data/server/lib/meta_worker.rb +360 -0
- data/server/lib/trigger.rb +34 -0
- metadata +110 -0
@@ -0,0 +1,195 @@
|
|
1
|
+
module BackgrounDRbMerb
|
2
|
+
class CronTrigger
|
3
|
+
WDAYS = { 0 => "Sunday",1 => "Monday",2 => "Tuesday",3 => "Wednesday", 4 => "Thursday", 5 => "Friday", 6 => "Saturday" }
|
4
|
+
LeapYearMonthDays = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
5
|
+
CommonYearMonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
6
|
+
|
7
|
+
attr_reader :sec, :min, :hour, :day, :month, :wday, :year, :cron_expr
|
8
|
+
|
9
|
+
def initialize(expr)
|
10
|
+
self.cron_expr = expr
|
11
|
+
end
|
12
|
+
|
13
|
+
def cron_expr=(expr)
|
14
|
+
@cron_expr = expr
|
15
|
+
self.sec, self.min, self.hour, self.day, self.month, self.wday, self.year = @cron_expr.split(' ')
|
16
|
+
end
|
17
|
+
|
18
|
+
def fire_after_time(p_time)
|
19
|
+
@t_sec,@t_min,@t_hour,@t_day,@t_month,@t_year,@t_wday,@t_yday,@t_idst,@t_zone = p_time.to_a
|
20
|
+
@count = 0
|
21
|
+
loop do
|
22
|
+
@count += 1
|
23
|
+
|
24
|
+
if @year && !@year.include?(@t_year)
|
25
|
+
return nil if @t_year > @year.max
|
26
|
+
@t_year = @year.detect { |y| y > @t_year }
|
27
|
+
end
|
28
|
+
|
29
|
+
# if range of months doesn't include current month, find next month from the range
|
30
|
+
unless @month.include?(@t_month)
|
31
|
+
next_month = @month.detect { |m| m > @t_month } || @month.min
|
32
|
+
@t_day,@t_hour,@t_min,@t_sec = @day.min,@hour.min,@min.min,@sec.min
|
33
|
+
if next_month < @t_month
|
34
|
+
@t_month = next_month
|
35
|
+
@t_year += 1
|
36
|
+
retry
|
37
|
+
end
|
38
|
+
@t_month = next_month
|
39
|
+
end
|
40
|
+
|
41
|
+
if !day_restricted? && wday_restricted?
|
42
|
+
unless @wday.include?(@t_wday)
|
43
|
+
next_wday = @wday.detect { |w| w > @t_wday} || @wday.min
|
44
|
+
@t_hour,@t_min,@t_sec = @hour.min,@min.min,@sec.min
|
45
|
+
t_time = Chronic.parse("next #{WDAYS[next_wday]}",:now => current_time)
|
46
|
+
@t_day,@t_month,@t_year = t_time.to_a[3..5]
|
47
|
+
@t_wday = next_wday
|
48
|
+
retry
|
49
|
+
end
|
50
|
+
elsif !wday_restricted? && day_restricted?
|
51
|
+
day_range = (1.. month_days(@t_year,@t_month))
|
52
|
+
# day array, that includes days which are present in current month
|
53
|
+
day_array = @day.select { |d| day_range === d }
|
54
|
+
unless day_array.include?(@t_day)
|
55
|
+
next_day = day_array.detect { |d| d > @t_day } || day_array.min
|
56
|
+
@t_hour,@t_min,@t_sec = @hour.min,@min.min,@sec.min
|
57
|
+
if !next_day || next_day < @t_day
|
58
|
+
t_time = Chronic.parse("next month",:now => current_time)
|
59
|
+
@t_day = next_day.nil? ? @day.min : next_day
|
60
|
+
@t_month,@t_year = t_time.month,t_time.year
|
61
|
+
retry
|
62
|
+
end
|
63
|
+
@t_day = next_day
|
64
|
+
end
|
65
|
+
else
|
66
|
+
# if both day and wday are restricted cron should give preference to one thats closer to current time
|
67
|
+
day_range = (1 .. month_days(@t_year,@t_month))
|
68
|
+
day_array = @day.select { |d| day_range === d }
|
69
|
+
if !day_array.include?(@t_day) && !@wday.include?(@t_wday)
|
70
|
+
next_day = day_array.detect { |d| d > @t_day } || day_array.min
|
71
|
+
next_wday = @wday.detect { |w| w > @t_wday } || @wday.min
|
72
|
+
@t_hour,@t_min,@t_sec = @hour.min,@min.min,@sec.min
|
73
|
+
|
74
|
+
# if next_day is nil or less than @t_day it means that it should run in next month
|
75
|
+
if !next_day || next_day < @t_day
|
76
|
+
next_time_mday = Chronic.parse("next month",:now => current_time)
|
77
|
+
else
|
78
|
+
@t_day = next_day
|
79
|
+
next_time_mday = current_time
|
80
|
+
end
|
81
|
+
next_time_wday = Chronic.parse("next #{WDAYS[next_wday]}",:now => current_time)
|
82
|
+
if next_time_mday < next_time_wday
|
83
|
+
@t_day,@t_month,@t_year = next_time_mday.to_a[3..5]
|
84
|
+
else
|
85
|
+
@t_day,@t_month,@t_year = next_time_wday.to_a[3..5]
|
86
|
+
end
|
87
|
+
retry
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
unless @hour.include?(@t_hour)
|
92
|
+
next_hour = @hour.detect { |h| h > @t_hour } || @hour.min
|
93
|
+
@t_min,@t_sec = @min.min,@sec.min
|
94
|
+
if next_hour < @t_hour
|
95
|
+
@t_hour = next_hour
|
96
|
+
next_day = Chronic.parse("next day",:now => current_time)
|
97
|
+
@t_day,@t_month,@t_year,@t_wday = next_day.to_a[3..6]
|
98
|
+
retry
|
99
|
+
end
|
100
|
+
@t_hour = next_hour
|
101
|
+
end
|
102
|
+
|
103
|
+
unless @min.include?(@t_min)
|
104
|
+
next_min = @min.detect { |m| m > @t_min } || @min.min
|
105
|
+
@t_sec = @sec.min
|
106
|
+
if next_min < @t_min
|
107
|
+
@t_min = next_min
|
108
|
+
next_hour = Chronic.parse("next hour",:now => current_time)
|
109
|
+
@t_hour,@t_day,@t_month,@t_year,@t_wday = next_hour.to_a[2..6]
|
110
|
+
retry
|
111
|
+
end
|
112
|
+
@t_min = next_min
|
113
|
+
end
|
114
|
+
|
115
|
+
unless @sec.include?(@t_sec)
|
116
|
+
next_sec = @sec.detect { |s| s > @t_sec } || @sec.min
|
117
|
+
if next_sec < @t_sec
|
118
|
+
@t_sec = next_sec
|
119
|
+
next_min = Chronic.parse("next minute",:now => current_time)
|
120
|
+
@t_min,@t_hour,@t_day,@t_month,@t_year,@t_wday = next_min.to_a[1..6]
|
121
|
+
retry
|
122
|
+
end
|
123
|
+
@t_sec = next_sec
|
124
|
+
end
|
125
|
+
break
|
126
|
+
end # end of loop do
|
127
|
+
current_time
|
128
|
+
end
|
129
|
+
|
130
|
+
def current_time
|
131
|
+
Time.local(@t_sec,@t_min,@t_hour,@t_day,@t_month,@t_year,@t_wday,nil,@t_idst,@t_zone)
|
132
|
+
end
|
133
|
+
|
134
|
+
def day_restricted?
|
135
|
+
return !@day.eql?(1..31)
|
136
|
+
end
|
137
|
+
|
138
|
+
def wday_restricted?
|
139
|
+
return !@wday.eql?(0..6)
|
140
|
+
end
|
141
|
+
|
142
|
+
# TODO: mimic attr_reader to define all of these
|
143
|
+
def sec=(sec); @sec = parse_part(sec, 0 .. 59); end
|
144
|
+
|
145
|
+
def min=(min); @min = parse_part(min, 0 .. 59); end
|
146
|
+
|
147
|
+
def hour=(hour); @hour = parse_part(hour, 0 .. 23); end
|
148
|
+
|
149
|
+
def day=(day)
|
150
|
+
@day = parse_part(day, 1 .. 31)
|
151
|
+
end
|
152
|
+
|
153
|
+
def month=(month)
|
154
|
+
@month = parse_part(month, 1 .. 12)
|
155
|
+
end
|
156
|
+
|
157
|
+
def year=(year)
|
158
|
+
@year = parse_part(year)
|
159
|
+
end
|
160
|
+
|
161
|
+
def wday=(wday)
|
162
|
+
@wday = parse_part(wday, 0 .. 6)
|
163
|
+
end
|
164
|
+
private
|
165
|
+
def month_days(y, m)
|
166
|
+
if ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0)
|
167
|
+
LeapYearMonthDays[m-1]
|
168
|
+
else
|
169
|
+
CommonYearMonthDays[m-1]
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# 0-5,8,10; 0-5; *; */5
|
174
|
+
def parse_part(part, range=nil)
|
175
|
+
return range if part.nil? or part == '*' or part =~ /^[*0]\/1$/
|
176
|
+
|
177
|
+
r = Array.new
|
178
|
+
part.split(',').each do |p|
|
179
|
+
if p =~ /-/ # 0-5
|
180
|
+
r << Range.new(*(p.scan(/\d+/).map { |x| x.to_i })).map { |x| x.to_i }
|
181
|
+
elsif p =~ /(\*|\d+)\/(\d+)/ && range # */5, 2/10
|
182
|
+
min = $1 == '*' ? 0 : $1.to_i
|
183
|
+
inc = $2.to_i
|
184
|
+
(min .. range.end).each_with_index do |x, i|
|
185
|
+
r << (range.begin == 1 ? x + 1 : x) if i % inc == 0
|
186
|
+
end
|
187
|
+
else
|
188
|
+
r << p.to_i
|
189
|
+
end
|
190
|
+
end
|
191
|
+
r.flatten
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class LogWorker < Packet::Worker
|
2
|
+
set_worker_name :log_worker
|
3
|
+
attr_accessor :log_file
|
4
|
+
|
5
|
+
def worker_init
|
6
|
+
file = Merb.root / "log" / "backgroundrb_#{CONFIG_FILE[:backgroundrb][:port]}.log"
|
7
|
+
@log_file = Merb::Logger.new(file, :debug, "", true)
|
8
|
+
end
|
9
|
+
|
10
|
+
def receive_data(p_data)
|
11
|
+
case p_data[:type]
|
12
|
+
when :request: process_request(p_data)
|
13
|
+
when :response: process_response(p_data)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def process_request(p_data)
|
18
|
+
log_data = p_data[:data]
|
19
|
+
@log_file << "[I] " + log_data
|
20
|
+
end
|
21
|
+
|
22
|
+
def process_response
|
23
|
+
puts "Not implemented and needed"
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,301 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
module BackgrounDRbMerb
|
3
|
+
# Class wraps a logger object for debugging internal errors within server
|
4
|
+
class DebugMaster
|
5
|
+
attr_accessor :log_mode,:logger,:log_flag
|
6
|
+
def initialize(log_mode,log_flag = true)
|
7
|
+
@log_mode = log_mode
|
8
|
+
@log_flag = log_flag
|
9
|
+
if @log_mode == :foreground
|
10
|
+
@logger = ::Logger.new(STDOUT)
|
11
|
+
else
|
12
|
+
@logger = ::Logger.new("#{Merb.root}/log/backgroundrb_#{CONFIG_FILE[:backgroundrb][:port]}_debug.log")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def info(data)
|
17
|
+
return unless @log_flag
|
18
|
+
@logger.info(data)
|
19
|
+
end
|
20
|
+
|
21
|
+
def debug(data)
|
22
|
+
return unless @log_flag
|
23
|
+
@logger.debug(data)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class MasterWorker
|
28
|
+
attr_accessor :debug_logger
|
29
|
+
def receive_data p_data
|
30
|
+
debug_logger.info(p_data)
|
31
|
+
@tokenizer.extract(p_data) do |b_data|
|
32
|
+
t_data = Marshal.load(b_data)
|
33
|
+
debug_logger.info(t_data)
|
34
|
+
case t_data[:type]
|
35
|
+
when :do_work: process_work(t_data)
|
36
|
+
when :get_status: process_status(t_data)
|
37
|
+
when :get_result: process_request(t_data)
|
38
|
+
when :start_worker: start_worker_request(t_data)
|
39
|
+
when :delete_worker: delete_drb_worker(t_data)
|
40
|
+
when :all_worker_status: query_all_worker_status(t_data)
|
41
|
+
when :worker_info: pass_worker_info(t_data)
|
42
|
+
when :all_worker_info: all_worker_info(t_data)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
def pass_worker_info(t_data)
|
49
|
+
worker_name_key = gen_worker_key(t_data[:worker],t_data[:job_key])
|
50
|
+
worker_instance = reactor.live_workers[worker_name_key]
|
51
|
+
info_response = { :worker => t_data[:worker],:job_key => t_data[:job_key]}
|
52
|
+
worker_instance ? (info_response[:status] = :running) : (info_response[:status] = :stopped)
|
53
|
+
send_object(info_response)
|
54
|
+
end
|
55
|
+
|
56
|
+
def all_worker_info(t_data)
|
57
|
+
info_response = []
|
58
|
+
reactor.live_workers.each do |key,value|
|
59
|
+
job_key = (value.worker_key.to_s).gsub(/#{value.worker_name}_?/,"")
|
60
|
+
info_response << { :worker => value.worker_name,:job_key => job_key,:status => :running }
|
61
|
+
end
|
62
|
+
send_object(info_response)
|
63
|
+
end
|
64
|
+
|
65
|
+
def query_all_worker_status(p_data)
|
66
|
+
dumpable_status = { }
|
67
|
+
reactor.live_workers.each { |key,value| dumpable_status[key] = reactor.result_hash[key] }
|
68
|
+
send_object(dumpable_status)
|
69
|
+
end
|
70
|
+
|
71
|
+
# FIXME: although worker key is removed nonetheless from live_workers hash
|
72
|
+
# it could be a good idea to remove it here itself.
|
73
|
+
def delete_drb_worker(t_data)
|
74
|
+
worker_name = t_data[:worker]
|
75
|
+
job_key = t_data[:job_key]
|
76
|
+
worker_name_key = gen_worker_key(worker_name,job_key)
|
77
|
+
begin
|
78
|
+
# ask_worker(worker_name,:job_key => t_data[:job_key],:type => :request, :data => { :worker_method => :exit})
|
79
|
+
worker_instance = reactor.live_workers[worker_name_key]
|
80
|
+
# pgid = Process.getpgid(worker_instance.pid)
|
81
|
+
Process.kill('TERM',worker_instance.pid)
|
82
|
+
# Process.kill('-TERM',pgid)
|
83
|
+
|
84
|
+
# Process.kill('KILL',worker_instance.pid)
|
85
|
+
rescue Packet::DisconnectError => sock_error
|
86
|
+
# reactor.live_workers.delete(worker_name_key)
|
87
|
+
reactor.remove_worker(sock_error)
|
88
|
+
rescue
|
89
|
+
debug_logger.info($!.to_s)
|
90
|
+
debug_logger.info($!.backtrace.join("\n"))
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def start_worker_request(p_data)
|
95
|
+
start_worker(p_data)
|
96
|
+
end
|
97
|
+
|
98
|
+
def process_work(t_data)
|
99
|
+
worker_name = t_data[:worker]
|
100
|
+
worker_name_key = gen_worker_key(worker_name,t_data[:job_key])
|
101
|
+
t_data.delete(:worker)
|
102
|
+
t_data.delete(:type)
|
103
|
+
begin
|
104
|
+
ask_worker(worker_name_key,:data => t_data, :type => :request, :result => false)
|
105
|
+
rescue Packet::DisconnectError => sock_error
|
106
|
+
reactor.live_workers.delete(worker_name_key)
|
107
|
+
rescue
|
108
|
+
debug_logger.info($!.to_s)
|
109
|
+
debug_logger.info($!.backtrace.join("\n"))
|
110
|
+
return
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
def process_status(t_data)
|
116
|
+
worker_name = t_data[:worker]
|
117
|
+
job_key = t_data[:job_key]
|
118
|
+
worker_name_key = gen_worker_key(worker_name,job_key)
|
119
|
+
status_data = reactor.result_hash[worker_name_key.to_sym]
|
120
|
+
send_object(status_data)
|
121
|
+
end
|
122
|
+
|
123
|
+
def process_request(t_data)
|
124
|
+
worker_name = t_data[:worker]
|
125
|
+
worker_name_key = gen_worker_key(worker_name,t_data[:job_key])
|
126
|
+
t_data.delete(:worker)
|
127
|
+
t_data.delete(:type)
|
128
|
+
begin
|
129
|
+
ask_worker(worker_name_key,:data => t_data, :type => :request,:result => true)
|
130
|
+
rescue Packet::DisconnectError => sock_error
|
131
|
+
reactor.live_workers.delete(worker_name_key)
|
132
|
+
rescue
|
133
|
+
debug_logger.info($!.to_s)
|
134
|
+
debug_logger.info($!.backtrace.join("\n"))
|
135
|
+
return
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# this method can receive one shot status reports or proper results
|
140
|
+
def worker_receive p_data
|
141
|
+
send_object(p_data)
|
142
|
+
end
|
143
|
+
|
144
|
+
def unbind
|
145
|
+
debug_logger.info("Client disconected")
|
146
|
+
end
|
147
|
+
def post_init
|
148
|
+
@tokenizer = BinParser.new
|
149
|
+
end
|
150
|
+
def connection_completed; end
|
151
|
+
end
|
152
|
+
|
153
|
+
class MasterProxy
|
154
|
+
attr_accessor :config_file,:reloadable_workers,:worker_triggers,:reactor
|
155
|
+
def initialize
|
156
|
+
raise "Running old Ruby version, upgrade to Ruby >= 1.8.5" unless check_for_ruby_version
|
157
|
+
@config_file = BackgrounDRbMerb::Config.read_config("#{Merb.root}/config/backgroundrb.yml")
|
158
|
+
|
159
|
+
log_flag = CONFIG_FILE[:backgroundrb][:debug_log].nil? ? true : CONFIG_FILE[:backgroundrb][:debug_log]
|
160
|
+
debug_logger = DebugMaster.new(CONFIG_FILE[:backgroundrb][:log],log_flag)
|
161
|
+
|
162
|
+
load_merb_env
|
163
|
+
|
164
|
+
find_reloadable_worker
|
165
|
+
|
166
|
+
Packet::Reactor.run do |t_reactor|
|
167
|
+
@reactor = t_reactor
|
168
|
+
enable_memcache_result_hash(t_reactor) if CONFIG_FILE[:backgroundrb][:result_storage] && CONFIG_FILE[:backgroundrb][:result_storage][:memcache]
|
169
|
+
t_reactor.start_worker(:worker => :log_worker) if log_flag
|
170
|
+
t_reactor.start_server(CONFIG_FILE[:backgroundrb][:ip],CONFIG_FILE[:backgroundrb][:port],MasterWorker) { |conn| conn.debug_logger = debug_logger }
|
171
|
+
t_reactor.next_turn { reload_workers }
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def gen_worker_key(worker_name,job_key = nil)
|
176
|
+
return worker_name if job_key.nil?
|
177
|
+
return "#{worker_name}_#{job_key}".to_sym
|
178
|
+
end
|
179
|
+
|
180
|
+
|
181
|
+
# method should find reloadable workers and load their schedule from config file
|
182
|
+
def find_reloadable_worker
|
183
|
+
t_workers = Dir["#{WORKER_ROOT}/**/*.rb"]
|
184
|
+
@reloadable_workers = t_workers.map do |x|
|
185
|
+
worker_name = File.basename(x,".rb")
|
186
|
+
require worker_name
|
187
|
+
worker_klass = Object.const_get(worker_name.camel_case)
|
188
|
+
worker_klass.reload_flag ? worker_klass : nil
|
189
|
+
end.compact
|
190
|
+
@worker_triggers = { }
|
191
|
+
@reloadable_workers.each do |t_worker|
|
192
|
+
schedule = load_reloadable_schedule(t_worker)
|
193
|
+
if schedule && !schedule.empty?
|
194
|
+
@worker_triggers[t_worker.worker_name.to_sym] = schedule
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def load_reloadable_schedule(t_worker)
|
200
|
+
worker_method_triggers = { }
|
201
|
+
worker_schedule = CONFIG_FILE[:schedules][t_worker.worker_name.to_sym]
|
202
|
+
|
203
|
+
worker_schedule && worker_schedule.each do |key,value|
|
204
|
+
case value[:trigger_args]
|
205
|
+
when String
|
206
|
+
cron_args = value[:trigger_args] || "0 0 0 0 0"
|
207
|
+
trigger = BackgrounDRbMerb::CronTrigger.new(cron_args)
|
208
|
+
when Hash
|
209
|
+
trigger = BackgrounDRbMerb::Trigger.new(value[:trigger_args])
|
210
|
+
end
|
211
|
+
worker_method_triggers[key] = { :trigger => trigger,:data => value[:data],:runtime => trigger.fire_after_time(Time.now).to_i }
|
212
|
+
end
|
213
|
+
worker_method_triggers
|
214
|
+
end
|
215
|
+
|
216
|
+
# method will reload workers that should be loaded on each schedule
|
217
|
+
def reload_workers
|
218
|
+
return if worker_triggers.empty?
|
219
|
+
worker_triggers.each do |key,value|
|
220
|
+
value.delete_if { |key,value| value[:trigger].respond_to?(:end_time) && value[:trigger].end_time <= Time.now }
|
221
|
+
end
|
222
|
+
|
223
|
+
worker_triggers.each do |worker_name,trigger|
|
224
|
+
trigger.each do |key,value|
|
225
|
+
time_now = Time.now.to_i
|
226
|
+
if value[:runtime] < time_now
|
227
|
+
load_and_invoke(worker_name,key,value)
|
228
|
+
t_time = value[:trigger].fire_after_time(Time.now)
|
229
|
+
value[:runtime] = t_time.to_i
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
# method will load the worker and invoke worker method
|
236
|
+
def load_and_invoke(worker_name,p_method,data)
|
237
|
+
begin
|
238
|
+
require worker_name.to_s
|
239
|
+
job_key = Packet::Guid.hexdigest
|
240
|
+
@reactor.start_worker(:worker => worker_name,:job_key => job_key)
|
241
|
+
worker_name_key = gen_worker_key(worker_name,job_key)
|
242
|
+
data_request = {:data => { :worker_method => p_method,:data => data[:data]},
|
243
|
+
:type => :request, :result => false
|
244
|
+
}
|
245
|
+
|
246
|
+
exit_request = {:data => { :worker_method => :exit},
|
247
|
+
:type => :request, :result => false
|
248
|
+
}
|
249
|
+
|
250
|
+
@reactor.live_workers[worker_name_key].send_request(data_request)
|
251
|
+
@reactor.live_workers[worker_name_key].send_request(exit_request)
|
252
|
+
rescue LoadError
|
253
|
+
puts "no such worker #{worker_name}"
|
254
|
+
rescue MissingSourceFile
|
255
|
+
puts "no such worker #{worker_name}"
|
256
|
+
return
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def load_merb_env
|
261
|
+
run_env = CONFIG_FILE[:backgroundrb][:environment] || 'development'
|
262
|
+
lazy_load = CONFIG_FILE[:backgroundrb][:lazy_load].nil? ? true : CONFIG_FILE[:backgroundrb][:lazy_load].nil?
|
263
|
+
require_merb_files unless lazy_load
|
264
|
+
ActiveRecord::Base.allow_concurrency = true if defined?(ActiveRecord)
|
265
|
+
end
|
266
|
+
|
267
|
+
def require_merb_files
|
268
|
+
debug_logger = DebugMaster.new(CONFIG_FILE[:backgroundrb][:log],true)
|
269
|
+
|
270
|
+
files = Dir["#{Merb.root}/app/models/**/*.rb"]
|
271
|
+
files.each { |x|
|
272
|
+
puts "***(M) #{x}"
|
273
|
+
begin
|
274
|
+
require x unless defined? x.camel_case
|
275
|
+
rescue LoadError
|
276
|
+
next
|
277
|
+
rescue MissingSourceFile
|
278
|
+
next
|
279
|
+
end
|
280
|
+
}
|
281
|
+
end
|
282
|
+
|
283
|
+
def enable_memcache_result_hash(t_reactor)
|
284
|
+
require 'memcache'
|
285
|
+
memcache_options = {
|
286
|
+
:c_threshold => 10_000,
|
287
|
+
:compression => true,
|
288
|
+
:debug => false,
|
289
|
+
:namespace => 'backgroundrb_result_hash',
|
290
|
+
:readonly => false,
|
291
|
+
:urlencode => false
|
292
|
+
}
|
293
|
+
cache = MemCache.new(memcache_options)
|
294
|
+
cache.servers = CONFIG_FILE[:backgroundrb][:result_storage][:memcache].split(',')
|
295
|
+
t_reactor.set_result_hash(cache)
|
296
|
+
end
|
297
|
+
|
298
|
+
def check_for_ruby_version; return RUBY_VERSION >= "1.8.5"; end
|
299
|
+
|
300
|
+
end # end of module BackgrounDRb
|
301
|
+
end
|