job_reactor 0.5.2 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4fe498b8b0ef18152ba17eaaae1b4907359c13f1
4
+ data.tar.gz: 4fcaed4b7cbe32e27b0dcbbd43cf00696f6458f9
5
+ SHA512:
6
+ metadata.gz: 75ebee033f02d15af6987a3f12cb69f2fdc8a61b8e3f8d72a30cfcbae0a542b901f0af89a6a105381b71cb164b7068624a65eed28605d6e109e8661aa257f173
7
+ data.tar.gz: f0b615f30c23efcfd851f28387e62ff650ab5b590bc05165df56cda72869852b869329a81845a3edae7e1373caaab28a30c72f9a5850b83aa75beeab626d8855
@@ -3,13 +3,10 @@ JobReactor <img src='https://secure.travis-ci.org/antonmi/job_reactor.png'>
3
3
 
4
4
  JobReactor is a library for creating, scheduling and processing background jobs.
5
5
  It is asynchronous client-server distributed system based on [EventMachine][0].
6
- Inspired by [Resque][1], [Beanstalkd][2] ([Stalker][3]), [DelayedJob][4], and etc.
7
6
 
8
- To use JobReactor with [Ruby on Rails][9] you should start distributor in initializer using `JR.run` method (it launches EventMachine in separate thread).
9
- Then add rake task(s) which will run the node(s). If you use [Thin][10] server the solution is more complicated because 'Thin' use EventMachine too.
10
- So, 'rails' integration is not complete for the time being.
11
- We need to test the system with different servers (clusters) and automate the initialization and re-start processes.
12
- Collaborators, you are welcome!
7
+ To use JobReactor with [Sinatra][11] or [Ruby on Rails][9] you should start distributor in initializer using `JR.run` method (it launches EventMachine in separate thread).
8
+ Then add rake task(s) which will run the node(s).
9
+ If you use server based on EventMachine such [Thin][12] use JR.wait_em_and_run method which will initialize JobReactor when EventMachine started.
13
10
 
14
11
  So, read the 'features' section and try JobReactor. You can do a lot with it.
15
12
 
@@ -76,7 +73,7 @@ end
76
73
  ```
77
74
  Run 'application.rb' in one terminal window and 'worker.rb' in another.
78
75
  Node connects to distributor, receives the job and works.
79
- Cool! But it was the simplest example. See 'examples' directory and read 'advanced usage'(coming soon).
76
+ Cool! But it was the simplest example. See 'examples' directory.
80
77
 
81
78
  Features
82
79
  =============
@@ -90,7 +87,7 @@ If you don't have many jobs you can leave only one node which will be connected
90
87
  Nodes and distributors are connected via TCP. So, you can run them on any machine you can connect to.
91
88
  Nodes may use different storage or the same one. You can store vitally important jobs in database and
92
89
  simple insignificant jobs in memory.
93
- And more: your nodes may create jobs for others nodes and communicate with each other. See page [advanced usage].
90
+ And more: You can run node and distributor inside one EMreactor, so your nodes may create jobs for others nodes and communicate with each other.
94
91
  3. Full job control
95
92
  -------------------
96
93
  You can add 'callback' and 'errbacks' to the job which will be called on the node.
@@ -111,9 +108,11 @@ If node is stopped or crashed it will retry stored jobs after start.
111
108
  6. EventMachine available
112
109
  -------------------------
113
110
  Remember, your jobs will be run inside EventMachine reactor! You can easily use the power of async nature of EventMachine.
114
- Use asynchronous [em-http-request][6], [em-websocket][7], [etc.], [etc.], and [etc].
111
+ Use asynchronous [em-http-request][6], [em-websocket][7], and etc.
115
112
  7. Thread safe
116
- Eventmachine reactor loop runs in one thread. So the code in jobs executed in the given node is absolutely threadsafe.
113
+ --------------
114
+ Eventmachine reactor loop runs in one thread. So the code in jobs executed in the given node is absolutely threadsafe.
115
+ The only exception is 'defer' job, when you tell the node to run job in EM.defer block (so job will be executed in separate thread).
117
116
  8. Deferred and periodic jobs
118
117
  -----------------------------
119
118
  You can use deferred jobs which will run 'after' some time or 'run_at' given time.
@@ -153,10 +152,10 @@ And now JobReactor is ready to work.
153
152
  ``` ruby
154
153
  JR.run! do
155
154
  JR.start_node({
156
- :storage => 'redis_storage',
157
- :name => 'redis_node1',
158
- :server => ['localhost', 5001],
159
- :distributors => [['localhost', 5000]]
155
+ storage: 'redis_storage',
156
+ name: 'redis_node1',
157
+ server: ['localhost', 5001],
158
+ distributors: [['localhost', 5000]]
160
159
  })
161
160
  end
162
161
  ```
@@ -179,6 +178,7 @@ JR.enqueue('my_job',{arg1: 1, arg2: 2}, {after: 20}, success, error)
179
178
 
180
179
  The first argument is the name of the job, the second is the arguments hash for the job.
181
180
  The third is the options hash. If you don't specify any option job will be instant job and will be sent to any free node. You can use the following options:
181
+ * `defer: true or false` - node will run the job in 'EM.defer' block. Be careful, the default threadpool size is 20 for EM. You can increase it by setting EM.threadpool_size = 'your value', but it is not recommended;
182
182
  * `after: seconds` - node will try run the job after `seconds` seconds;
183
183
  * `run_at: time` - node will try run the job at given time;
184
184
  * `period: seconds` - node will run job periodically, each `seconds` seconds;
@@ -198,8 +198,10 @@ Example:
198
198
  ```ruby
199
199
  #in your 'job_file'
200
200
  job 'my_job' do |args|
201
- #do smth
202
- args.merge!(result: 'Yay!')
201
+ #do smth
202
+ args.merge!(result: 'Yay!')
203
+ end
204
+
203
205
  #in your application
204
206
  #success feedback
205
207
  success = proc {|args| puts args}
@@ -293,14 +295,15 @@ __Note__, feedbacks are kept in memory in your application, so they disappear wh
293
295
 
294
296
  Job Storage
295
297
  ==========
296
- Now you can store your job in [Redis][5] storage (`'redis_storage`') or in memory (`'memory_storage'`).
298
+ Now you can store your jobs in [Redis][5] storage (`'redis_storage`') or in memory (`'memory_storage'`).
299
+ We use [em-hiredis](https://github.com/mloughran/em-hiredis) gem
297
300
  Only the first, of course, 'really' persists the jobs. You can use the last one if you don't want install Redis, don't need retry jobs and need more speed (by the way, the difference in performance is not so great - Redis is very fast).
301
+ You can easily integrate your own storage. Just make it EventMachine compatible.
298
302
 
299
- The default host and port for Redis server are:
303
+ The default url for Redis server are:
300
304
 
301
305
  ```ruby
302
- JR.config[:redis_host] = 'localhost'
303
- JR.config[:redis_port] = 6379
306
+ JR.config[:hiredis_url] = "redis://127.0.0.1:6379/0"
304
307
  ```
305
308
 
306
309
  JobReactor works asynchronously with Redis using [em-redis][8] library to increase the speed.
@@ -314,6 +317,7 @@ The informaion about jobs is saved several times during processing. This informa
314
317
  * failed_at - the time when job was failed;
315
318
  * last_error - the error occured;
316
319
  * period - period (for periodic jobs);
320
+ * defer - 'true' or 'false', flag to run job in EM.defer block;
317
321
  * status - job status ('new', 'in progress', 'queued', 'complete', 'error', 'failed', 'cancelled');
318
322
  * attempt - the number of attempt;
319
323
  * make_after - when to start job again (in seconds after last save);
@@ -332,6 +336,16 @@ JR.config[:retry_jobs_at_start] = true
332
336
  ```
333
337
 
334
338
  We provide simple `JR::RedisMonitor` module to check the Redis storage from irb console (or from your app).
339
+ We use synchronous [redis](https://github.com/redis/redis-rb) gem.
340
+ Connect to Redis by:
341
+
342
+ ```ruby
343
+ JR.config[:redis_host] = 'localhost'
344
+ JR.config[:redis_port] = 6379
345
+ ```
346
+
347
+
348
+
335
349
  See methods:
336
350
 
337
351
  ```ruby
@@ -344,7 +358,7 @@ JR::RedisMonitor.destroy_all_jobs_for(node_name)
344
358
 
345
359
  License
346
360
  =======
347
- The MIT License - Copyright (c) 2012 Anton Mishchuk
361
+ The MIT License - Copyright (c) 2012-2013 Anton Mishchuk
348
362
 
349
363
  [0]: http://rubyeventmachine.com
350
364
  [1]: https://github.com/defunkt/resque
@@ -357,3 +371,5 @@ The MIT License - Copyright (c) 2012 Anton Mishchuk
357
371
  [8]: https://github.com/madsimian/em-redis
358
372
  [9]: http://rubyonrails.org/
359
373
  [10]: http://code.macournoyer.com/thin/
374
+ [11]: http://www.sinatrarb.com/
375
+ [12]: http://code.macournoyer.com/thin/
@@ -1,6 +1,6 @@
1
1
  require 'eventmachine'
2
2
  require 'job_reactor/job_reactor'
3
- require 'job_reactor/logger'
3
+ require 'job_reactor/job_logger'
4
4
  require 'job_reactor/node'
5
5
  require 'job_reactor/distributor'
6
6
 
@@ -15,27 +15,37 @@ require 'job_reactor/distributor'
15
15
  module JobReactor
16
16
  extend self
17
17
 
18
- def run(&block)
18
+ def run
19
19
  Thread.new do
20
20
  if EM.reactor_running?
21
- block.call if block_given?
21
+ yield if block_given?
22
22
  JR.ready!
23
23
  else
24
24
  EM.run do
25
- block.call if block_given?
25
+ yield if block_given?
26
26
  JR.ready!
27
27
  end
28
28
  end
29
29
  end
30
30
  end
31
31
 
32
- def run!(&block)
32
+ def run!
33
33
  if EM.reactor_running?
34
- block.call if block_given?
34
+ yield if block_given?
35
35
  JR.ready!
36
36
  else
37
37
  EM.run do
38
- block.call if block_given?
38
+ yield if block_given?
39
+ JR.ready!
40
+ end
41
+ end
42
+ end
43
+
44
+ def wait_em_and_run
45
+ Thread.new do
46
+ sleep(0.1) until EM.reactor_running?
47
+ EM.schedule do
48
+ yield if block_given?
39
49
  JR.ready!
40
50
  end
41
51
  end
@@ -10,27 +10,27 @@ module JobReactor
10
10
  # EM::PeriodicTimer.new(10) { JR::Logger.log nodes}.
11
11
  #
12
12
  def nodes
13
- @@nodes ||= []
13
+ @nodes ||= []
14
14
  end
15
15
 
16
16
  # Contains connections pool - all node connections.
17
17
  #
18
18
  def connections
19
- @@connections ||= []
19
+ @connections ||= []
20
20
  end
21
21
 
22
22
  def server
23
- @@connect_to || "#{@@host}:#{@@port}"
23
+ @connect_to || "#{@host}:#{@port}"
24
24
  end
25
25
 
26
26
  # Starts distributor on given hast and port.
27
27
  # See JR.start_distributor documentation.
28
28
  #
29
29
  def start(host, port, opts = {})
30
- @@connect_to = opts[:connect_to] && opts[:connect_to].join(':')
31
- @@host = host
32
- @@port = port
33
- JR::Logger.log "Distributor listens #{host}:#{port}"
30
+ @connect_to = opts[:connect_to] && opts[:connect_to].join(':')
31
+ @host = host
32
+ @port = port
33
+ JR::JobLogger.log "Distributor listens #{host}:#{port}"
34
34
  EM.start_server(host, port, JobReactor::Distributor::Server)
35
35
  end
36
36
 
@@ -44,7 +44,7 @@ module JobReactor
44
44
  data = Marshal.dump(hash)
45
45
  connection.send_data(data)
46
46
  connection.lock
47
- JR::Logger.log "Distributor sent job '#{hash['name']}' to '#{connection.name}'"
47
+ JR::JobLogger.log "Distributor sent job '#{hash['name']}' to '#{connection.name}'"
48
48
  else
49
49
  EM.next_tick do
50
50
  send_data_to_node(hash)
@@ -31,7 +31,7 @@ module JobReactor
31
31
  end
32
32
 
33
33
  def unbind
34
- JR::Logger.log "#{@name} disconnected"
34
+ JR::JobLogger.log "#{@name} disconnected"
35
35
  close_connection
36
36
  JobReactor::Distributor.connections.delete(self)
37
37
  end
@@ -4,14 +4,14 @@ module JobReactor
4
4
  class Server < EM::Connection
5
5
 
6
6
  def post_init
7
- JR::Logger.log 'Begin node handshake'
7
+ JR::JobLogger.log 'Begin node handshake'
8
8
  end
9
9
 
10
10
  def receive_data(data)
11
11
  data = Marshal.load(data)
12
12
  if data[:node_info]
13
13
  node_info = data[:node_info]
14
- JR::Logger.log "Receive data from node: #{data[:node_info]}"
14
+ JR::JobLogger.log "Receive data from node: #{data[:node_info]}"
15
15
  JobReactor::Distributor.nodes << node_info
16
16
  connection = EM.connect(*node_info[:server], Client, node_info[:name])
17
17
  JobReactor::Distributor.connections << connection
@@ -1,23 +1,27 @@
1
1
  module JobReactor
2
- module Logger
2
+ module JobLogger
3
3
 
4
4
  # Sets the output stream
5
5
  #
6
- @@logger_method = JR.config[:logger_method]
6
+ def self.logger_method
7
+ @logger_method ||= JR.config[:logger_method]
8
+ end
7
9
 
8
10
  def self.stdout=(value)
9
- @@stdout = value
11
+ @stdout = value
10
12
  end
11
13
 
12
14
  def self.stdout
13
- @@stdout ||= $stdout
15
+ @stdout ||= $stdout
14
16
  end
15
17
 
16
18
  # Logs message to output stream
17
19
  #
18
20
  def self.log(msg)
19
- stdout.public_send(@@logger_method, '-'*100)
20
- stdout.public_send(@@logger_method, msg)
21
+ if logger_method
22
+ stdout.public_send(logger_method, "-----#{Time.now.utc}-----")
23
+ stdout.public_send(logger_method, msg)
24
+ end
21
25
  end
22
26
 
23
27
  # Builds string for job event and log it
@@ -22,18 +22,18 @@ module JobReactor
22
22
  # Accessors to jobs.
23
23
  #
24
24
  def jobs
25
- @@jobs ||= { }
25
+ @jobs ||= { }
26
26
  end
27
27
 
28
28
  # Ready flag.
29
- # @@ready is true when block is called inside EM reactor.
29
+ # @ready is true when block is called inside EM reactor.
30
30
  #
31
31
  def ready!
32
- @@ready = true
32
+ @ready = true
33
33
  end
34
34
 
35
35
  def ready?
36
- (@@ready ||= false) && EM.reactor_running?
36
+ (@ready ||= false) && EM.reactor_running?
37
37
  end
38
38
 
39
39
  # Parses jobs.
@@ -66,11 +66,11 @@ module JobReactor
66
66
  end
67
67
 
68
68
  def succ_feedbacks
69
- @@succ_feedbacks ||= { }
69
+ @succ_feedbacks ||= { }
70
70
  end
71
71
 
72
72
  def err_feedbacks
73
- @@err_feedbacks ||= { }
73
+ @err_feedbacks ||= { }
74
74
  end
75
75
 
76
76
  # Here is the only method user can call inside the application (excepts start-up methods, of course).
@@ -90,6 +90,9 @@ module JobReactor
90
90
  # JR.enqueue 'job', {arg1: 'arg1', arg2: 'arg2'}
91
91
  #
92
92
  # You can add the following options:
93
+ # :defer - run job in EM.defer block (in separate thread). Default is false.
94
+ # Be careful, the default threadpool size is 20 for EM.
95
+ # You can increase it by setting EM.threadpool_size = 'your value', but it is not recommended.
93
96
  # :run_at - run at given time;
94
97
  # :after - run after some time (in seconds);
95
98
  # :period - will make periodic job which will be launched every opts[:period] seconds;
@@ -97,7 +100,7 @@ module JobReactor
97
100
  # :not_node - to do not send job to the node;
98
101
  #
99
102
  # Example:
100
- # JR.enqueue 'job', {arg1: 'arg1'}, {period: 100, node: 'my_favorite_node'}
103
+ # JR.enqueue 'job', {arg1: 'arg1'}, {period: 100, node: 'my_favorite_node', defer: true}
101
104
  # JR.enqueue 'job', {arg1: 'arg1'}, {after: 10, not_node: 'some_node'}
102
105
  #
103
106
  # You can add 'success feedback' and 'error feedback'. We use term 'feedback' to distinguish them from callbacks and errbacks which are executed on the node side.
@@ -109,7 +112,7 @@ module JobReactor
109
112
  # error = proc { |args| result = args }
110
113
  # JR.enqueue 'job', { arg1: 'arg1'}, {}, success, error
111
114
  #
112
- def enqueue(name, args = { }, opts = { }, success_proc = nil, error_proc = nil)
115
+ def enqueue(name, args = {}, opts = {}, success_proc = nil, error_proc = nil)
113
116
  hash = { 'name' => name, 'args' => args, 'attempt' => 0, 'status' => 'new', 'defer' => 'false' }
114
117
 
115
118
  hash.merge!('period' => opts[:period]) if opts[:period]
@@ -121,7 +124,7 @@ module JobReactor
121
124
 
122
125
  hash.merge!('distributor' => JR::Distributor.server)
123
126
 
124
- hash.merge!('defer' => 'true') if opts[:defer]
127
+ hash.merge!('defer' => opts[:defer] ? 'true' : 'false')
125
128
 
126
129
  add_succ_feedbacks!(hash, success_proc) if success_proc.is_a? Proc
127
130
  add_err_feedbacks!(hash, error_proc) if error_proc.is_a? Proc
@@ -219,7 +222,7 @@ module JobReactor
219
222
  #
220
223
  def add_start_callback(job)
221
224
  job.callback do
222
- JR::Logger.log_event(:start, job)
225
+ JR::JobLogger.log_event(:start, job)
223
226
  end
224
227
  end
225
228
 
@@ -227,7 +230,7 @@ module JobReactor
227
230
  #
228
231
  def add_last_callback(job)
229
232
  job.callback do
230
- JR::Logger.log_event(:complete, job)
233
+ JR::JobLogger.log_event(:complete, job)
231
234
  end
232
235
  end
233
236
 
@@ -235,7 +238,7 @@ module JobReactor
235
238
  #
236
239
  def add_start_errback(job)
237
240
  job.errback do
238
- JR::Logger.log_event(:error, job)
241
+ JR::JobLogger.log_event(:error, job)
239
242
  end
240
243
  end
241
244
 
@@ -243,7 +246,7 @@ module JobReactor
243
246
  #
244
247
  def add_complete_errback(job)
245
248
  job.errback do
246
- JR::Logger.log_event(:error_complete, job)
249
+ JR::JobLogger.log_event(:error_complete, job)
247
250
  end
248
251
  end
249
252
 
@@ -1,8 +1,6 @@
1
- # Names are informative
2
- # TODO
3
1
  module JobReactor
4
2
  def self.config
5
- @@config ||= {}
3
+ @config ||= {}
6
4
  end
7
5
  end
8
6
 
@@ -19,15 +17,8 @@ JR.config[:remove_done_jobs] = true
19
17
  JR.config[:remove_cancelled_jobs] = true
20
18
  JR.config[:remove_failed_jobs] = false
21
19
 
20
+ JR.config[:hiredis_url] = "redis://localhost:6379"
22
21
  JR.config[:redis_host] = 'localhost'
23
22
  JR.config[:redis_port] = 6379
24
23
 
25
- JR.config[:logger_method] = :puts
26
-
27
- #TODO next releases with rails support
28
- #JR.config[:active_record_adapter] = 'mysql2'
29
- #JR.config[:active_record_database] = 'em'
30
- #JR.config[:active_record_user] = ''
31
- #JR.config[:active_record_password] = ''
32
- #JR.config[:active_record_table_name] = 'reactor_jobs'
33
- #JR.config[:use_custom_active_record_connection] = true
24
+ JR.config[:logger_method] = :puts #nil for complete disable any messages
@@ -1,9 +1,7 @@
1
1
  module JobReactor
2
2
 
3
- class NoSuchJob < RuntimeError
4
- end
5
- class CancelJob < Exception
6
- end
3
+ class NoSuchJob < RuntimeError; end
4
+ class CancelJob < Exception; end
7
5
 
8
6
  end
9
7
 
@@ -17,10 +17,11 @@
17
17
  # errbacks: [[]]
18
18
  # }
19
19
  # }
20
+ #
20
21
  # Names of callbacks and errbacks are optional and may be used just for description
21
22
  #
22
23
  # Job and job_callbacks are absolutely identical on the node side.
23
- # They become callback of the Deferrable instance. 'job' is the first callback, 'job_callbacks' are the next
24
+ # They become callbacks of the Deferrable instance. 'job' is the first callback, 'job_callbacks' are the next
24
25
  #
25
26
  # Use job_callbacks to split your job into small parts.
26
27
  # You can send additional arguments from one callback to another by merging them into 'args'.
@@ -35,7 +36,7 @@
35
36
  # end
36
37
  #
37
38
  # This is true for errbacks too. Note that you can't access additional arguments added in callbacks in your errbacks
38
- # In errbacks you also have :error key in args which point the error message
39
+ # In errbacks you also have :error key in args which point the error message.
39
40
  #
40
41
  # Note, that callbacks and errbacks are called one after another synchronously in one EM tick.
41
42
  #
@@ -3,22 +3,17 @@
3
3
  # save(hash).
4
4
  # load(hash).
5
5
  # destroy(hash).
6
- # jobs_for(name).
6
+ # jobs_for(name). The method is called when node starts.
7
7
  # The last one is used when node is restarting to retry saved jobs.
8
8
  # The storage may not be thread safe, because each node manage it own jobs and don't now anything about others.
9
9
 
10
10
  # Defines storages for lazy loading
11
11
 
12
- # TODO
13
- # require 'active_record'
14
- # class JobReactor::ActiveRecordStorage < ::ActiveRecord::Base; end
15
-
16
12
  module JobReactor::MemoryStorage; end
17
13
  module JobReactor::RedisStorage; end
18
14
 
19
15
  module JobReactor
20
16
  STORAGES = {
21
- #'active_record_storage' => JobReactor::ActiveRecordStorage,
22
17
  'memory_storage' => JobReactor::MemoryStorage,
23
18
  'redis_storage' => JobReactor::RedisStorage
24
19
  }
@@ -4,7 +4,13 @@ module JobReactor
4
4
  class Node
5
5
 
6
6
  def initialize(opts)
7
- @config = { storage: opts[:storage], name: opts[:name], server: opts[:server], connect_to: opts[:connect_to], distributors: opts[:distributors]}
7
+ @config = {
8
+ storage: opts[:storage],
9
+ name: opts[:name],
10
+ server: opts[:server],
11
+ connect_to: opts[:connect_to],
12
+ distributors: opts[:distributors]
13
+ }
8
14
  end
9
15
 
10
16
  def config
@@ -45,7 +51,7 @@ module JobReactor
45
51
  #
46
52
  def connect_to(distributor)
47
53
  if connections[distributor]
48
- JR::Logger.log "Searching for distributor #{distributor.join(' ')}"
54
+ JR::JobLogger.log "Searching for distributor #{distributor.join(' ')}"
49
55
  connections[distributor].reconnect(*distributor)
50
56
  else
51
57
  connections.merge!(distributor => EM.connect(*distributor, Client, self, distributor))
@@ -8,7 +8,7 @@ module JobReactor
8
8
  end
9
9
 
10
10
  def post_init
11
- JR::Logger.log("Searching for distributor: #{@distributor.join(' ')} ...")
11
+ JR::JobLogger.log("Searching for distributor: #{@distributor.join(' ')} ...")
12
12
  end
13
13
 
14
14
  def lock
@@ -34,7 +34,7 @@ module JobReactor
34
34
  # Sends node credentials to distributor.
35
35
  #
36
36
  def connection_completed
37
- JR::Logger.log('Begin distributor handshake')
37
+ JR::JobLogger.log('Begin distributor handshake')
38
38
  data = {node_info: {name: @node.config[:name], server: @node.server} }
39
39
  data = Marshal.dump(data)
40
40
  send_data(data)
@@ -13,7 +13,7 @@ module JobReactor
13
13
  #Ok, node is connected and ready to work
14
14
  #
15
15
  def post_init
16
- JR::Logger.log("#{@node.name} ready to work")
16
+ JR::JobLogger.log("#{@node.name} ready to work")
17
17
  end
18
18
 
19
19
  # It is the place where job life cycle begins.
@@ -25,7 +25,7 @@ module JobReactor
25
25
  #
26
26
  def receive_data(data)
27
27
  hash = Marshal.load(data)
28
- JR::Logger.log("#{@node.name} received job: #{hash}")
28
+ JR::JobLogger.log("#{@node.name} received job: #{hash}")
29
29
  hash.merge!('node' => @node.name)
30
30
  @storage.save(hash) do |hash|
31
31
  @node.schedule(hash)
@@ -2,37 +2,36 @@
2
2
  module JobReactor
3
3
  module MemoryStorage
4
4
 
5
- @@storage = { }
6
5
 
7
6
  class << self
8
7
  def storage
9
- @@storage
8
+ @storage ||= {}
10
9
  end
11
10
 
12
- def load(hash, &block)
11
+ def load(hash)
13
12
  hash = storage[hash['id']]
14
13
  if hash
15
- hash_copy = { }
14
+ hash_copy = {}
16
15
  hash.each { |k, v| hash_copy.merge!(k => v) }
17
- block.call(hash_copy) if block_given?
16
+ yield hash_copy if block_given?
18
17
  end
19
18
  end
20
19
 
21
- def save(hash, &block)
20
+ def save(hash)
22
21
  unless (hash['id'])
23
22
  id = Time.now.to_f.to_s
24
23
  hash.merge!('id' => id)
25
24
  end
26
25
  storage.merge!(hash['id'] => hash)
27
26
 
28
- block.call(hash) if block_given?
27
+ yield hash if block_given?
29
28
  end
30
29
 
31
30
  def destroy(hash)
32
31
  storage.delete(hash['id'])
33
32
  end
34
33
 
35
- def jobs_for(name, &block) #No persistance
34
+ def jobs_for(name, &block) #No persistence
36
35
  nil
37
36
  end
38
37
  end
@@ -2,12 +2,12 @@ require 'redis'
2
2
  module JobReactor
3
3
  module RedisMonitor
4
4
 
5
- ATTRS = %w(id name args last_error run_at failed_at attempt period make_after status distributor on_success on_error)
5
+ ATTRS = %w(id name args last_error run_at failed_at attempt period make_after status distributor on_success on_error defer)
6
6
 
7
7
  extend self
8
8
 
9
9
  def storage
10
- @@storage ||= Redis.new(host: JR.config[:redis_host], port: JR.config[:redis_port])
10
+ @storage ||= Redis.new(host: JR.config[:redis_host], port: JR.config[:redis_port])
11
11
  end
12
12
 
13
13
  # Returns all job for given node.
@@ -1,21 +1,19 @@
1
1
  # TODO comment it
2
- require 'em-redis'
2
+ require 'em-hiredis'
3
3
 
4
4
  module JobReactor
5
5
  module RedisStorage
6
- @@storage = EM::Protocols::Redis.connect(host: JobReactor.config[:redis_host], port: JobReactor.config[:redis_port])
7
6
  ATTRS = %w(id name args last_error run_at failed_at attempt period make_after status distributor on_success on_error defer)
8
7
 
9
8
  class << self
10
9
 
11
10
  def storage
12
- @@storage
11
+ @storage ||= EM::Hiredis.connect(JobReactor.config[:hiredis_url])
13
12
  end
14
13
 
15
- def load(hash, &block)
14
+ def load(hash)
16
15
  key = "#{hash['node']}_#{hash['id']}"
17
16
  hash_copy = {'node' => hash['node']} #need new object, because old one has been 'failed'
18
-
19
17
  storage.hmget(key, *ATTRS) do |record|
20
18
  unless record.compact.empty?
21
19
  ATTRS.each_with_index do |attr, i|
@@ -26,26 +24,26 @@ module JobReactor
26
24
  end
27
25
  hash_copy['args'] = Marshal.load(hash_copy['args'])
28
26
 
29
- block.call(hash_copy) if block_given?
27
+ yield hash_copy if block_given?
30
28
  end
31
29
  end
32
30
  end
33
31
 
34
-
35
- def save(hash, &block)
32
+ def save(hash)
36
33
  hash.merge!('id' => Time.now.to_f.to_s) unless hash['id']
37
34
  key = "#{hash['node']}_#{hash['id']}"
38
35
  args, hash['args'] = hash['args'], Marshal.dump(hash['args'])
39
36
 
40
37
  storage.hmset(key, *ATTRS.map{|attr| [attr, hash[attr]]}.flatten) do
41
38
  hash['args'] = args
42
-
43
- block.call(hash) if block_given?
39
+ yield hash if block_given?
44
40
  end
45
41
  end
46
42
 
47
43
  def destroy(hash)
48
- storage.del("#{hash['node']}_#{hash['id']}")
44
+ storage.del("#{hash['node']}_#{hash['id']}") do
45
+ yield hash if block_given?
46
+ end
49
47
  end
50
48
 
51
49
  def destroy_all_jobs_for(name)
@@ -53,7 +51,7 @@ module JobReactor
53
51
  storage.del(*storage.keys(pattern))
54
52
  end
55
53
 
56
- def jobs_for(name, &block)
54
+ def jobs_for(name)
57
55
  pattern = "*#{name}_*"
58
56
  storage.keys(pattern) do |keys|
59
57
  keys.each do |key|
@@ -64,7 +62,7 @@ module JobReactor
64
62
  self.load(hash) do |hash|
65
63
  if hash['status'] != 'complete' && hash['status'] != 'cancelled' && hash['status'] != 'failed'
66
64
  else
67
- block.call(hash)
65
+ yield hash if block_given?
68
66
  end
69
67
  end
70
68
  end
metadata CHANGED
@@ -1,113 +1,104 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: job_reactor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
5
- prerelease:
4
+ version: 0.6.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Anton Mishchuk
9
- - Andrey Rozhkovskiy
10
8
  autorequire:
11
9
  bindir: bin
12
10
  cert_chain: []
13
- date: 2012-09-18 00:00:00.000000000 Z
11
+ date: 2013-06-21 00:00:00.000000000 Z
14
12
  dependencies:
15
13
  - !ruby/object:Gem::Dependency
16
14
  name: eventmachine
17
15
  requirement: !ruby/object:Gem::Requirement
18
- none: false
19
16
  requirements:
20
- - - ! '>='
17
+ - - '>='
21
18
  - !ruby/object:Gem::Version
22
19
  version: '0'
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
- none: false
27
23
  requirements:
28
- - - ! '>='
24
+ - - '>='
29
25
  - !ruby/object:Gem::Version
30
26
  version: '0'
31
27
  - !ruby/object:Gem::Dependency
32
28
  name: redis
33
29
  requirement: !ruby/object:Gem::Requirement
34
- none: false
35
30
  requirements:
36
- - - ! '>='
31
+ - - '>='
37
32
  - !ruby/object:Gem::Version
38
33
  version: '0'
39
34
  type: :runtime
40
35
  prerelease: false
41
36
  version_requirements: !ruby/object:Gem::Requirement
42
- none: false
43
37
  requirements:
44
- - - ! '>='
38
+ - - '>='
45
39
  - !ruby/object:Gem::Version
46
40
  version: '0'
47
41
  - !ruby/object:Gem::Dependency
48
- name: em-redis
42
+ name: em-hiredis
49
43
  requirement: !ruby/object:Gem::Requirement
50
- none: false
51
44
  requirements:
52
- - - ! '>='
45
+ - - '>='
53
46
  - !ruby/object:Gem::Version
54
47
  version: '0'
55
48
  type: :runtime
56
49
  prerelease: false
57
50
  version_requirements: !ruby/object:Gem::Requirement
58
- none: false
59
51
  requirements:
60
- - - ! '>='
52
+ - - '>='
61
53
  - !ruby/object:Gem::Version
62
54
  version: '0'
63
- description: ! " JobReactor is a library for creating, scheduling and processing
64
- background jobs.\n It is asynchronous client-server distributed system based
65
- on EventMachine.\n Inspired by DelayedJob, Resque, Beanstalkd, and etc.\n"
55
+ description: |2
56
+ JobReactor is a library for creating, scheduling and processing background jobs.
57
+ It is asynchronous client-server distributed system based on EventMachine.
66
58
  email: anton.mishchuk@gmial.com
67
59
  executables: []
68
60
  extensions: []
69
61
  extra_rdoc_files: []
70
62
  files:
71
- - lib/job_reactor.rb
72
- - lib/job_reactor/node/server.rb
63
+ - lib/job_reactor/job_reactor/job_parser.rb
64
+ - lib/job_reactor/job_reactor/config.rb
65
+ - lib/job_reactor/job_reactor/exceptions.rb
66
+ - lib/job_reactor/job_reactor/storages.rb
67
+ - lib/job_reactor/storages/redis_storage.rb
68
+ - lib/job_reactor/storages/redis_monitor.rb
69
+ - lib/job_reactor/storages/memory_storage.rb
70
+ - lib/job_reactor/distributor/client.rb
71
+ - lib/job_reactor/distributor/server.rb
72
+ - lib/job_reactor/job_logger.rb
73
73
  - lib/job_reactor/node/client.rb
74
+ - lib/job_reactor/node/server.rb
74
75
  - lib/job_reactor/node.rb
75
76
  - lib/job_reactor/job_reactor.rb
76
- - lib/job_reactor/distributor/server.rb
77
- - lib/job_reactor/distributor/client.rb
78
- - lib/job_reactor/storages/redis_monitor.rb
79
- - lib/job_reactor/storages/memory_storage.rb
80
- - lib/job_reactor/storages/redis_storage.rb
81
77
  - lib/job_reactor/distributor.rb
82
- - lib/job_reactor/logger.rb
83
- - lib/job_reactor/job_reactor/storages.rb
84
- - lib/job_reactor/job_reactor/exceptions.rb
85
- - lib/job_reactor/job_reactor/job_parser.rb
86
- - lib/job_reactor/job_reactor/config.rb
78
+ - lib/job_reactor.rb
87
79
  - README.markdown
88
80
  homepage: http://github.com/antonmi/job_reactor
89
81
  licenses: []
82
+ metadata: {}
90
83
  post_install_message:
91
84
  rdoc_options: []
92
85
  require_paths:
93
86
  - lib
94
87
  required_ruby_version: !ruby/object:Gem::Requirement
95
- none: false
96
88
  requirements:
97
- - - ! '>='
89
+ - - '>='
98
90
  - !ruby/object:Gem::Version
99
91
  version: '0'
100
92
  required_rubygems_version: !ruby/object:Gem::Requirement
101
- none: false
102
93
  requirements:
103
- - - ! '>='
94
+ - - '>='
104
95
  - !ruby/object:Gem::Version
105
96
  version: '0'
106
97
  requirements: []
107
98
  rubyforge_project:
108
- rubygems_version: 1.8.24
99
+ rubygems_version: 2.0.3
109
100
  signing_key:
110
- specification_version: 3
101
+ specification_version: 4
111
102
  summary: Simple, powerful and high scalable job queueing and background workers system
112
103
  based on EventMachine
113
104
  test_files: []