Changeset 323
- Timestamp:
- 03/11/08 18:30:43 (5 months ago)
- Files:
-
- trunk (modified) (1 prop)
- trunk/.svnignore (added)
- trunk/doc/content/bugs/bugs.txt (modified) (1 diff)
- trunk/doc/content/bugs/bugs.yaml (modified) (1 diff)
- trunk/doc/content/community/community.txt (modified) (1 diff)
- trunk/doc/content/community/community.yaml (modified) (1 diff)
- trunk/doc/content/content.txt (modified) (8 diffs)
- trunk/doc/content/rails/rails.txt (modified) (6 diffs)
- trunk/doc/content/scheduling/scheduling.txt (modified) (8 diffs)
- trunk/lib/backgroundrb/bdrb_config.rb (modified) (2 diffs)
- trunk/script/backgroundrb (modified) (2 diffs)
- trunk/server/lib/master_worker.rb (modified) (8 diffs)
- trunk/tasks/backgroundrb_tasks.rake (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk
- Property svn:ignore set to
rdoc
- Property svn:ignore set to
trunk/doc/content/bugs/bugs.txt
r319 r323 6 6 You can also submit potential patches that fix known bugs or add exciting features to the above trac url. 7 7 8 Also, if you are using older version of _BackgrounDRb_ and having a problem, why not upgrade to latest code from git, your bug 8 Also, if you are using older version of _BackgrounDRb_ and having a problem, why not upgrade to latest code from git, your bug 9 9 might have been fixed there. 10 11 %(entry-title)<a name="known_bugs">Known Problems </a>% 12 13 Since _BackgrounDRb_ has feature of thread pools, which allows users to execute tasks 14 concurrently, we are using @allow_concurrency = true@ in @ActiveRecord@ model objects. 15 This has been known to create some issues with Oracle database Adapters. If you are sure of 16 what you are doing and don't need thread pool feature, you can go ahead and remove @allow_concurrency = true@ 17 from _BackgrounDRb_ code and it should work. 10 18 11 19 </div> trunk/doc/content/bugs/bugs.yaml
r319 r323 3 3 # Custom 4 4 title: "Report Bugs" 5 sidebar_items: [["Trac", "#trac"] ]5 sidebar_items: [["Trac", "#trac"], ["KnownBugs", "#known_bugs"]] trunk/doc/content/community/community.txt
r319 r323 22 22 Its a perfect place for discussing new ideas, asking questions, submitting patches and stuff. 23 23 24 %(entry-title)<a name="irc"> IRC Help </a>% 25 26 You can also try #backgroundrb on freenode for help. 27 28 %(entry-title)<a name="contribute"> Contribute </a>% 29 30 Your contributions/feedback is most welcome. We have very simple rule for giving new coders 31 commit access. If you submit one patch which is accepted for inclusion in the _BackgrounDRb_ 32 code repository, you are elligible for commit access. Create an account on "Gitorious":http://gitorious.org/ 33 and let me (gethemant at gmail dot com) know your login handle. 34 24 35 </div> 25 36 trunk/doc/content/community/community.yaml
r319 r323 3 3 # Custom 4 4 title: "Join the BackgrounDRb Community" 5 sidebar_items: [["People", "people"], ["MailingList", "#mailing_list"] ]5 sidebar_items: [["People", "people"], ["MailingList", "#mailing_list"], ["IRC", "#irc"], ["Contribute", "#contribute"]] trunk/doc/content/content.txt
r319 r323 11 11 %(entry-title)<a name="installation"> Installation </a>% 12 12 13 *Update::* 14 There was a small error in _BackgrounDRb_ startup script, because of which you may not be 15 able to start _BackgrounDRb_ server. Its been fixed in git and svn trunks. Hence, make sure 16 that you are running latest code from git or svn trunks. Also, after checking out code from repo, 17 don't forget to remove old 'backgroundrb' script from script directory of rails application 18 and run @rake backgroundrb:setup@ 19 13 20 p(sub-title). Installing the dependencies : 14 21 … … 19 26 20 27 Please note that, this version of _BackgrounDRb_ needs packet version 0.1.5 or greater, so make 21 sure you have that. 28 sure you have that. 22 29 23 30 p(sub-title). Getting the code from Subversion : … … 41 48 42 49 After getting the plugin, you must configure it for use. _BackgrounDRb_ comes with a rake task 43 for automating plugin configuration. Run, following command from root directory of your rails 44 application, after installation: 50 for automating plugin configuration. Before running rake task, remove if any old 'backgroundrb' 51 script is there in script folder of your rails app after that run, following command from 52 root directory of your rails application, after installation: 45 53 46 54 <pre class="boxed">rake backgroundrb:setup </pre> … … 67 75 :backgroundrb: 68 76 :port: 11006 69 :ip: 0.0.0.0 77 :ip: 0.0.0.0 70 78 :environment: production </pre> 71 79 … … 80 88 :environment: production # rails environment to load 81 89 :log: foreground # foreground mode,print log messages on console 82 :lazy_load: true # do not load models eagerly 83 :debug_log: false # disable log workers and other logging </pre> 90 :lazy_load: false # load models eagerly 91 :debug_log: false # disable log workers and other logging 92 :schedules: # optional task scheduling 93 : # look in scheduling section </pre> 84 94 85 @lazy_load@ option should be true if you want to pass @ActiveRecord@ model86 objects around, However, this option is generally not encouraged to use, 87 because if your model makes use of some other ActiveRecord plugin and 88 plugin is not available during load, loading of model will fail. In 89 new version of BackgrounDRb its generally discouraged to pass model objects around, 95 @lazy_load@ option should be false if you want to pass @ActiveRecord@ model 96 objects around, However, this option is generally not encouraged to use, 97 because if your model makes use of some other ActiveRecord plugin and 98 plugin is not available during load, loading of model will fail. In 99 new version of BackgrounDRb its generally discouraged to pass model objects around, 90 100 since they are harder to serialize and deserialize. 101 102 It is possible to set options depending on the environment: 103 104 <pre class="multiline"> 105 :backgroundrb: 106 :ip: 0.0.0.0 107 108 :development: 109 :backgroundrb: 110 :port: 11111 # use port 11111 111 :log: foreground # foreground mode,print log messages on console 112 113 :production: 114 :backgroundrb: 115 :port: 22222 # use port 22222 116 :lazy_load: true # do not load models eagerly 117 :debug_log: false # disable log workers and other logging </pre> 118 119 This will cause @script/backgroundrb@ to use port 11111 and to log to foreground under 120 development environment and @script/backgroundrb -e production@ to use port 22222, 121 lazy_load and no debug_log under production environment. The ip 0.0.0.0 is used in all 122 environments. 123 91 124 92 125 %(entry-title)<a name="worker"> Workers </a>% … … 102 135 create lib/workers/billing_worker.rb </pre> 103 136 104 And generated worker will look like: 137 And generated worker will look like: 105 138 106 139 <pre class="multiline">class BillingWorker < BackgrounDRb::MetaWorker 107 140 set_worker_name :billing_worker 108 141 def create(args = nil) 109 # method gets called, when new instance of worker is created. 142 # method gets called, when new instance of worker is created. 110 143 end 111 144 end </pre> … … 120 153 # this method is called, when worker is loaded for the first time 121 154 end 122 155 123 156 def charge_customer(customer_id = nil) 124 157 logger.info 'charging customer now' … … 159 192 160 193 161 162 194 195 trunk/doc/content/rails/rails.txt
r319 r323 16 16 p(sub-title). Invoke an asynchronous task on a worker : 17 17 18 Let's say, you have following worker code: 19 20 <pre class="multiline">class FooWorker < BackgrounDRb::MetaWorker 21 set_worker_name :foo_worker 22 def create(args = nil) 23 # this method is called, when worker is loaded for the first time 24 end 25 26 def some_task args 27 # perform a long running task 28 end 29 end 30 </pre> 31 32 And you want to invoke @some_task@ method with appropriate arguments from rails. 18 33 Following snippet will invoke method @some_task@ with argument @data@ in @foo_worker@. Also, method will 19 34 be invoked asychrounously and Rails won't wait for result from BackgrounDRb server. … … 22 37 worker.some_task(data) </pre> 23 38 24 Here, I would like to illustrate a point that contrary to general percenption, since @some_task@ method is being 25 executed asyhcrounously, don't expect any meaningful return values from second line. 39 It should be noted that, since @some_task@ method is being 40 executed asyhcrounously, don't expect any meaningful return values from method invocation. 41 If you want to invoke a method on worker and collect results returned by it, you 42 should read next section (Invoke method and collect results). 26 43 27 44 When you invoke @MiddleMan.worker(:foo_worker)@ it returns a worker proxy, hence you can combine above two lines in … … 35 52 p(sub-title). Invoke a method on worker and get results : 36 53 37 Following snippet will invoke method @some_task@ with argument @data@ in @foo_worker@. Also, method block54 Following snippet will invoke method @some_task@ with argument @data@ in @foo_worker@. Also, method will block 38 55 until BackgrounDRb server returns a result. 39 56 40 57 <pre class="multiline">worker = MiddleMan.worker(:foo_worker) 41 58 result = worker.some_task(data,true) </pre> 59 60 Since, now you are expecting a return value from your worker method, new worker code will look like: 61 62 <pre class="multiline">class FooWorker < BackgrounDRb::MetaWorker 63 set_worker_name :foo_worker 64 def create(args = nil) 65 # this method is called, when worker is loaded for the first time 66 end 67 68 def some_task args 69 billing_result = UserPayment.bill! 70 return billing_result 71 end 72 end 73 </pre> 42 74 43 75 As illustrated above, you can use @job_key@ or make them in single line too. When you are invoking a method … … 47 79 p(sub-title). Fetch Status/Result Objects of a worker : 48 80 49 If you are using @register_status@ in your worker code to store status/result objects, you can retrieve them from 81 If you are using @register_status@ in your worker code to store status/result objects, you can retrieve them from 50 82 rails using: 51 83 52 84 <pre class="boxed">status_obj = MiddleMan.worker(:foo_worker).ask_status </pre> 53 85 54 You can as usual use @job_key@ if *worker was started with a job_key*. 86 You can as usual use @job_key@ if *worker was started with a job_key*. 55 87 56 88 You can query status/result objects of all workers in one shot. For example, in your controller: 57 89 58 <pre class="multiline"> def ask_status90 <pre class="multiline">def ask_status 59 91 t_response = MiddleMan.query_all_workers 60 92 running_workers = t_response.map { |key,value| "#{key} = #{value}"}.join(',') … … 75 107 Important thing to be kept in mind is, when you are creating a worker using above approach, you 76 108 must use a unique @job_key@ while starting the worker. Also, while invoking any of the other methods 77 like @ask_status@, @worker_info@ or one of the worker methods, you must use @job_key@.109 like @ask_status@, @worker_info@ or one of the worker methods, you must user same @job_key@. 78 110 79 111 Also another complicated example of starting a worker will be: … … 85 117 86 118 Above code will start @error_worker@ with @job_key@ and will pass argument @:data@ to @create@ 87 method of the worker. Worker will be scheduled to run @hello_world@ method every 5 seconds with argument 119 method of the worker. Worker will be scheduled to run @hello_world@ method every 5 seconds with argument 88 120 specified in @:data@. 89 121 trunk/doc/content/scheduling/scheduling.txt
r319 r323 3 3 %(entry-title)<a name="simple_schedule"> Timer Based Scheduling </a>% 4 4 5 Simple tasks in the workers can be scheduled using @add_timer@ and@add_periodic_timer@ methods.5 Simple tasks in the workers can be scheduled using @add_timer@ or @add_periodic_timer@ methods. 6 6 For example: 7 7 8 8 <pre class="multiline">class HelloWorker < BackgrounDRb::MetaWorker 9 9 set_worker_name :hello_worker 10 10 11 11 def create(args = nil) 12 12 # time argument is in seconds 13 13 add_periodic_timer(10) { expire_sessions } 14 14 end 15 15 16 16 def expire_sessions 17 17 # expire user sessions … … 19 19 end </pre> 20 20 21 Similar one can use @add_timer@ to fire oneshot task execution.21 Similarly one can use @add_timer@ to fire oneshot task execution. 22 22 23 23 %(entry-title)<a name="unix_scheduler"> Unix Scheduler </a>% … … 26 26 from @backgroundrb.yml@ file. A sample configuration looks like: 27 27 28 <pre class="multiline">:backgroundrb: 28 <pre class="multiline">:backgroundrb: 29 29 :ip: 0.0.0.0 30 30 :port: 11006 31 :schedules:32 :foo_worker:33 :foobar:34 :trigger_args:35 :start: <%= Time.now + 5.seconds %>36 :end: <%= Time.now + 10.minutes %>37 :repeat_interval: <%= 1.minute %> </pre>31 :schedules: 32 :foo_worker: 33 :foobar: 34 :trigger_args: 35 :start: <%= Time.now + 5.seconds %> 36 :end: <%= Time.now + 10.minutes %> 37 :repeat_interval: <%= 1.minute %> </pre> 38 38 39 39 Above scheduler option schedules method @foobar@ defined inside @foo_worker@ to start … … 44 44 %(entry-title)<a name="cron_scheduling"> Cron Scheduling </a>% 45 45 46 _BackgrounDRb_ also supports Cron based ccheduling. 46 _BackgrounDRb_ also supports Cron based ccheduling. 47 47 You can use a configuration file for cron scheduling of workers. The method specified in the configuration 48 48 file would be called periodically. You should accommodate for the fact that the time gap between periodic … … 53 53 A Sample Configuration file for Cron based Scheduling looks like: 54 54 55 <pre class="multiline">:schedules: 55 <pre class="multiline"> 56 :backgroundrb: 57 :ip: 0.0.0.0 58 :port: 11006 59 :schedules: 56 60 :foo_worker: 57 61 :barbar: … … 61 65 62 66 Above scheduler will schedule invocation of @barbar@ method inside @foo_worker@ at every 10 seconds. 67 You can also schedule invocation of multiple methods in same worker at different intervals, just use 68 following as an example configuration file. 63 69 64 p(sub-title). A Word about Cron Scheduler 70 <pre class="multiline"> 71 :backgroundrb: 72 :ip: 0.0.0.0 73 :port: 11006 74 :schedules: 75 :foo_worker: 76 :barbar: 77 :trigger_args: */10 * * * * * 78 :data: Hello World 79 :some_task: # execute some_method in foo_worker every 2nd hour 80 :trigger_args: 0 * */2 * * * 81 :data: Hello World </pre> 82 83 84 p(sub-title). A Word about Cron Scheduler 65 85 66 86 Note that the initial field in the BackgrounDRb cron trigger specifies … … 109 129 it will trigger every second for the subsequent match. 110 130 111 p(sub-title). Loading Workers on demand 131 p(sub-title). Loading Workers on demand 112 132 113 133 Usually when your worker is scheduled to execute at longer intervals, it 114 134 doesn't make sense to have worker around, when its doing nothing. Since, scheduling 115 135 via configuration file requires that your worker must be loaded when _BackgrounDRb_ starts, 116 your worker is always around, even when doing nothing. 136 your worker is always around, even when doing nothing. 117 137 118 You can reuse worker in processing requests from rails, but if its not possible 138 You can reuse worker in processing requests from rails, but if its not possible 119 139 and you rather want worker to start afresh each time, scheduler detects a firetime, you can use 120 140 following syntax to autostart workers on scheduled time: … … 123 143 set_worker_name :hello_worker 124 144 reload_on_schedule true 125 145 126 146 def create(args = nil) 127 147 # this method is called, when worker is loaded for the first time trunk/lib/backgroundrb/bdrb_config.rb
r321 r323 3 3 4 4 class BackgrounDRb::Config 5 def self.parse_cmd_options 5 def self.parse_cmd_options(argv) 6 6 require 'optparse' 7 7 options = { :environment => (ENV['RAILS_ENV'] || "development").dup } … … 20 20 opts.on("-v","--version", 21 21 "Show version.") { $stderr.puts "1.0.3"; exit } 22 end.parse! 22 end.parse!(argv) 23 23 24 24 ENV["RAILS_ENV"] = options[:environment] trunk/script/backgroundrb
r322 r323 10 10 11 11 require RAILS_HOME + '/config/boot.rb' 12 13 # parse CLI options and set RAILS_ENV before loading RoR environment 14 require "bdrb_config.rb" 15 BackgrounDRb::Config.parse_cmd_options ARGV 16 17 require RAILS_HOME + '/config/environment' 12 18 require "rubygems" 13 19 require "yaml" … … 16 22 require "packet" 17 23 require "backgroundrb_server" 18 require "bdrb_config.rb"19 24 20 BackgrounDRb::Config.parse_cmd_options21 25 CONFIG_FILE = BackgrounDRb::Config.read_config("#{RAILS_HOME}/config/backgroundrb.yml") 22 26 pid_file = "#{RAILS_HOME}/tmp/pids/backgroundrb_#{CONFIG_FILE[:backgroundrb][:port]}.pid" trunk/server/lib/master_worker.rb
r319 r323 156 156 raise "Running old Ruby version, upgrade to Ruby >= 1.8.5" unless check_for_ruby_version 157 157 @config_file = BackgrounDRb::Config.read_config("#{RAILS_HOME}/config/backgroundrb.yml") 158 158 159 159 log_flag = CONFIG_FILE[:backgroundrb][:debug_log].nil? ? true : CONFIG_FILE[:backgroundrb][:debug_log] 160 160 debug_logger = DebugMaster.new(CONFIG_FILE[:backgroundrb][:log],log_flag) 161 161 162 162 load_rails_env 163 163 164 164 find_reloadable_worker 165 165 166 166 Packet::Reactor.run do |t_reactor| 167 167 @reactor = t_reactor … … 172 172 end 173 173 end 174 174 175 175 def gen_worker_key(worker_name,job_key = nil) 176 176 return worker_name if job_key.nil? … … 178 178 end 179 179 180 180 181 181 # method should find reloadable workers and load their schedule from config file 182 182 def find_reloadable_worker … … 196 196 end 197 197 end 198 198 199 199 def load_reloadable_schedule(t_worker) 200 200 worker_method_triggers = { } 201 201 worker_schedule = CONFIG_FILE[:schedules][t_worker.worker_name.to_sym] 202 202 203 203 worker_schedule && worker_schedule.each do |key,value| 204 204 case value[:trigger_args] … … 220 220 value.delete_if { |key,value| value[:trigger].respond_to?(:end_time) && value[:trigger].end_time <= Time.now } 221 221 end 222 222 223 223 worker_triggers.each do |worker_name,trigger| 224 224 trigger.each do |key,value| … … 232 232 end 233 233 end 234 234 235 235 # method will load the worker and invoke worker method 236 236 def load_and_invoke(worker_name,p_method,data) … … 241 241 worker_name_key = gen_worker_key(worker_name,job_key) 242 242 data_request = {:data => { :worker_method => p_method,:data => data[:data]}, 243 :type => :request, :result => false 243 :type => :request, :result => false 244 244 } 245 245 246 246 exit_request = {:data => { :worker_method => :exit}, 247 :type => :request, :result => false 247 :type => :request, :result => false 248 248 } 249 249 250 250 @reactor.live_workers[worker_name_key].send_request(data_request) 251 251 @reactor.live_workers[worker_name_key].send_request(exit_request) 252 252 rescue LoadError 253 puts "no such worker #{worker_name}" 253 puts "no such worker #{worker_name}" 254 254 rescue MissingSourceFile 255 puts "no such worker #{worker_name}" 255 puts "no such worker #{worker_name}" 256 256 return 257 257 end … … 264 264 RAILS_ENV.replace(run_env) if defined?(RAILS_ENV) 265 265 require RAILS_HOME + '/config/environment.rb' 266 load_rails_models unless CONFIG_FILE[:backgroundrb][:lazy_load] 266 lazy_load = CONFIG_FILE[:backgroundrb][:lazy_load].nil? ? true : CONFIG_FILE[:backgroundrb][:lazy_load].nil? 267 p lazy_load 268 load_rails_models unless lazy_load 267 269 ActiveRecord::Base.allow_concurrency = true 268 270 end trunk/tasks/backgroundrb_tasks.rake
r319 r323 8 8 FileUtils.chmod 0774, script_src 9 9 10 defaults = {:backgroundrb => {:ip => ' localhost',:port => 11006 } }10 defaults = {:backgroundrb => {:ip => '0.0.0.0',:port => 11006 } } 11 11 12 12 config_dest = "#{RAILS_ROOT}/config/backgroundrb.yml"
