| | 36 | Use rake task for initial configuration: |
|---|
| | 37 | |
|---|
| | 38 | * Cron style scheduling and config |
|---|
| | 39 | |
|---|
| | 40 | | :backgroundrb: |
|---|
| | 41 | | :ip: localhost |
|---|
| | 42 | | :port: 11006 |
|---|
| | 43 | | |
|---|
| | 44 | | :schedules: |
|---|
| | 45 | | :foo_worker: |
|---|
| | 46 | | :worker_method: foobar |
|---|
| | 47 | | :trigger_args: */5 * * * * * * |
|---|
| | 48 | |
|---|
| | 49 | * Normal Unix scheduler |
|---|
| | 50 | | :backgroundrb: |
|---|
| | 51 | | :ip: localhost |
|---|
| | 52 | | :port: 11006 |
|---|
| | 53 | | :schedules: |
|---|
| | 54 | | :foo_worker: |
|---|
| | 55 | | :start: <%= Time.now + 5.seconds %> |
|---|
| | 56 | | :end: <%= Time.now + 10.minutes %> |
|---|
| | 57 | | :repeat_interval: 1.minute |
|---|
| | 58 | |
|---|
| | 59 | * Plain config |
|---|
| | 60 | | :backgroundrb: |
|---|
| | 61 | | :ip: localhost |
|---|
| | 62 | | :port: 11006 |
|---|
| | 63 | |
|---|
| | 64 | === Scheduling |
|---|
| | 65 | There are three schemes for periodic execution and scheduling. |
|---|
| | 66 | - Cron Scheduling |
|---|
| | 67 | You can use configuration file for cron scheduling of workers. Method specified in configuration |
|---|
| | 68 | file would be called periodically. You should take care of the fact that, time gap between periodic |
|---|
| | 69 | invocation of a method should be more than the time thats actually required to execute the method. |
|---|
| | 70 | If a method takes longer time than the time window specified, your method invocations would lag |
|---|
| | 71 | perpetually. |
|---|
| | 72 | - Normal Scheduler |
|---|
| | 73 | You can use second form of scheduling as shown in config file. |
|---|
| | 74 | - add_periodic_timer method |
|---|
| | 75 | A third and very basic form of scheduling that you can use is, "add_periodic_timer" method. You can call |
|---|
| | 76 | method from anywhere in your worker. |
|---|
| | 77 | |
|---|
| | 78 | def create |
|---|
| | 79 | add_periodic_timer(5) { say_hello } |
|---|
| | 80 | end |
|---|
| | 81 | |
|---|
| | 82 | Above snippet would register the proc for periodic execution at every 5 seconds. |
|---|
| | 83 | |
|---|
| | 84 | === Code |
|---|
| | 85 | Install the plugin, and run setup task. Create a worker, using worker generator. |
|---|
| | 86 | |
|---|
| | 87 | ./script/generatr worker bar |
|---|
| | 88 | |
|---|
| | 89 | You will have a bar_worker.rb in your RAILS_ROOT/lib/workers/( called WORKER_ROOT henceforth ). |
|---|
| | 90 | Generated code will look like this: |
|---|
| | 91 | |
|---|
| | 92 | class BarWorker < BackgrounDRb::MetaWorker |
|---|
| | 93 | set_worker_name :bar_worker |
|---|
| | 94 | def create |
|---|
| | 95 | # this method is called, when worker is loaded for the first time |
|---|
| | 96 | puts "starting a bar worker" |
|---|
| | 97 | end |
|---|
| | 98 | |
|---|
| | 99 | def process_request(p_data) |
|---|
| | 100 | user_input = p_data[:data] |
|---|
| | 101 | result = self.send(user_input[:method],user_input[:data]) |
|---|
| | 102 | send_response(p_data,result) |
|---|
| | 103 | end |
|---|
| | 104 | end |
|---|
| | 105 | |
|---|
| | 106 | 'create' method gets called, when worker is loaded and created. Each worker runs in its |
|---|
| | 107 | own process and you can use 'create' for initializing worker specific stuff. |
|---|
| | 108 | All the requests, send from rails, to bdrb would be received in process_request method. |
|---|
| | 109 | Received data, contains client address as well, which will be used to send the response |
|---|
| | 110 | back to client. You just need to extract the data from received data and call appropriate |
|---|
| | 111 | method. Once, you are done with executing your method, you can use "send_response" to send |
|---|
| | 112 | the result back to client ( rails in our case ). |
|---|
| | 113 | |
|---|
| | 114 | It should be noted that, you must pass original data as an parameter with send_response |
|---|
| | 115 | method because original data contains client address. |
|---|
| | 116 | |
|---|
| | 117 | Following code snippet, would ask bdrb to execute method 'add_values' in 'foo_worker' with |
|---|
| | 118 | arguments '10+10' and return the result. |
|---|
| | 119 | |
|---|
| | 120 | p MiddleMan.send_request(:worker => :foo_worker, :method => :add_values,:data => "10+10") |
|---|
| | 121 | |
|---|
| | 122 | You can also use register_status as described in following snippet to register status of |
|---|
| | 123 | your worker with master, which can be directly queried from rails. |
|---|
| | 124 | |
|---|
| | 125 | register_status(some_status_data) |
|---|
| | 126 | |
|---|
| | 127 | From rails, you can query status object using following code: |
|---|
| | 128 | |
|---|
| | 129 | MiddleMan.ask_status(:worker => :foo_worker) |
|---|
| | 130 | |
|---|
| | 131 | Above code would return status object of 'foo_worker'. When you call register_status |
|---|
| | 132 | from a worker, it replaces older state of the worker with master. Since, master process |
|---|
| | 133 | stores status of the worker, all the status queries are served by master itself. It can be |
|---|
| | 134 | used to store result hashes and stuff. Unlike previous versions of bdrb, there shouldn't be |
|---|
| | 135 | any data corruption. |
|---|
| | 136 | |
|---|
| | 137 | === Legacy and deprecated stuff |
|---|
| | 138 | |
|---|
| | 139 | Although, You need to wrap your head a bit for understanding "evented" model of network programming a bit, |
|---|
| | 140 | but it gets easier once you get the hang of it. Much of the older stuff is deprecated. Here is a brief list: |
|---|
| | 141 | |
|---|
| | 142 | - ACL : gone, trust to thy firewalls. |
|---|
| | 143 | - Runtime scheduling through MiddleMan proxy object. |
|---|
| | 144 | I don't know if many people used this feature, and is probably easy to implement back. |
|---|
| | 145 | - Threads: find .|grep 'Thread' , gone |
|---|
| | 146 | - Passing of arguments from configuration file. |
|---|
| | 147 | Again, I am not sure many people used it either, if you are passing arguments to periodic |
|---|
| | 148 | methods from configuration files, you may as well hardcode that argument in worker itself. |
|---|
| | 149 | |
|---|
| | 150 | Some people, asked, if we can do "progress bar" or "file_upload" with new code base. The answer is yes, but |
|---|
| | 151 | again, changes would be required. "progress bar" example would look like this: |
|---|
| | 152 | |
|---|
| | 153 | class ProgressWorker < BackgrounDRb::MetaWorker |
|---|
| | 154 | set_worker_name :progress_worker |
|---|
| | 155 | def create |
|---|
| | 156 | @counter = 0 |
|---|
| | 157 | add_peridic_timer(2) { increment_counter } |
|---|
| | 158 | end |
|---|
| | 159 | def increment_counter |
|---|
| | 160 | @counter += 1 |
|---|
| | 161 | register_status(@counter) |
|---|
| | 162 | end |
|---|
| | 163 | end |
|---|
| | 164 | |
|---|
| | 165 | And using MiddleMan proxy, you can keep queering status of your progress bar: |
|---|
| | 166 | |
|---|
| | 167 | MiddleMan.ask_status(:worker => :progress_worker) |
|---|
| | 168 | |
|---|
| | 169 | I would welcome, anyone who contributes more examples back. You can even use callbacks |
|---|
| | 170 | or Deferable pattern for invoking callbacks. |
|---|
| | 171 | |
|---|
| | 172 | === Exciting new stuff |
|---|
| | 173 | * Rock solid stable. |
|---|
| | 174 | * Master is using a hash for storing status of each worker. I am thinking of adding something like this: |
|---|
| | 175 | |
|---|
| | 176 | #backgroundrb.yml |
|---|
| | 177 | status_storage: |
|---|
| | 178 | storage: db |
|---|
| | 179 | database: worker_status |
|---|
| | 180 | * Each worker comes with Event loop of its own and can potentially do lots of fancy stuff. Two noteworthy methods are: |
|---|
| | 181 | |
|---|
| | 182 | connect(ip,port,Handler) |
|---|
| | 183 | start_worker(ip,port,Handler) |
|---|
| | 184 | |
|---|
| | 185 | If you are familiar with EventMachine or Twisted style of network programming, above methods allow you to |
|---|
| | 186 | start tcp servers inside your workers or lets you connect to external tcp servers. For Each accepted client or |
|---|
| | 187 | connected socket a instance of Handler class would be created and integrated with main event loop. |
|---|
| | 188 | This can be used for worker to worker communication between backgroundrb servers running on two machines. |
|---|
| | 189 | |
|---|
| | 190 | You are encouraged to look into framework directory, and see the code that implements all this stuff.Guts of |
|---|
| | 191 | new bdrb is based on this library, which would be released soon as separately. |
|---|