job_reactor 0.5.0.beta3 → 0.5.0.beta4
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/README.markdown
CHANGED
@@ -5,9 +5,9 @@ Now we are in beta (need to complete documentation and fix some bugs)
|
|
5
5
|
|
6
6
|
JobReactor is a library for creating, scheduling and processing background jobs.
|
7
7
|
It is asynchronous client-server distributed system based on [EventMachine][0].
|
8
|
-
Inspired by Resque, Stalker, DelayedJob, and etc.
|
8
|
+
Inspired by [Resque][1], [Stalker][2], [DelayedJob][3], and etc.
|
9
9
|
|
10
|
-
JobReactor
|
10
|
+
JobReactor has not 'rails' integration for the time being.
|
11
11
|
But it is very close. We need test the system with different servers (clusters) and automatize initialization and restart processes.
|
12
12
|
Collaborators, you are welcome!
|
13
13
|
|
@@ -17,6 +17,9 @@ Quick start
|
|
17
17
|
===========
|
18
18
|
Use `gem install job_reactor --pre` to try it.
|
19
19
|
|
20
|
+
You need to install [Redis][6] if you want to persist your jobs.
|
21
|
+
``$ sudo apt-get install redis-server ``
|
22
|
+
|
20
23
|
In you main application:
|
21
24
|
`application.rb`
|
22
25
|
``` ruby
|
@@ -51,7 +54,7 @@ end
|
|
51
54
|
```
|
52
55
|
Run 'application.rb' in one terminal window and 'worker.rb' in another.
|
53
56
|
Node connects to distributor, receives the job and works.
|
54
|
-
Cool! But it was the simplest example. See 'examples' directory and read
|
57
|
+
Cool! But it was the simplest example. See 'examples' directory and read 'advanced usage'(coming soon).
|
55
58
|
|
56
59
|
Features
|
57
60
|
=============
|
@@ -63,9 +66,9 @@ If you don't have many jobs you can leave only one node which will be connected
|
|
63
66
|
2. High scalability
|
64
67
|
-------------------
|
65
68
|
Nodes and distributors are connected via TCP. So, you can run them on any machine you can connect to.
|
66
|
-
Nodes may use different storage or the same one.
|
69
|
+
Nodes may use different storage or the same one. You can store vitally important jobs in database and
|
67
70
|
simple insignificant jobs in memory.
|
68
|
-
And more: your nodes may create jobs for others nodes and communicate with each other. See page [
|
71
|
+
And more: your nodes may create jobs for others nodes and communicate with each other. See page [advanced usage].
|
69
72
|
3. Full job control
|
70
73
|
-------------------
|
71
74
|
You can add callback and errbacks to the job which will be called on the node.
|
@@ -83,7 +86,7 @@ If node is stopped or crashed it will retry stored jobs after start.
|
|
83
86
|
5. EventMachine available
|
84
87
|
-------------------------
|
85
88
|
Remember, your jobs will be run inside EventMachine reactor! You can easily use the power of async nature of EventMachine.
|
86
|
-
Use asynchronous [http
|
89
|
+
Use asynchronous [em-http-request][4], [em-websocket][5], [etc.], [etc.], and [etc]. See page [advance usage].
|
87
90
|
6. Deferred and periodic jobs
|
88
91
|
-----------------------------
|
89
92
|
You can use deferred jobs which will run 'after' some time or 'run_at' given time.
|
@@ -102,7 +105,7 @@ If no nodes are specified distributor will try to send the job to the first free
|
|
102
105
|
10. Node based priorities
|
103
106
|
-----------------------
|
104
107
|
There are no priorities like in Delayed::Job or Stalker. Bud there are flexible node-based priorities.
|
105
|
-
You can specify the node which should execute the job. You can reserve several nodes for high priority jobs.
|
108
|
+
You can specify the node which should execute the job and the node is forbidden for given job. You can reserve several nodes for high priority jobs.
|
106
109
|
|
107
110
|
|
108
111
|
|
@@ -125,9 +128,17 @@ How it works
|
|
125
128
|
#TODO
|
126
129
|
|
127
130
|
|
131
|
+
License
|
132
|
+
---------
|
133
|
+
The MIT License - Copyright (c) 2012 Anton Mishchuk
|
134
|
+
|
128
135
|
|
129
136
|
|
130
137
|
|
131
|
-
|
132
|
-
|
133
|
-
[
|
138
|
+
[0]: http://rubyeventmachine.com
|
139
|
+
[1]: https://github.com/defunkt/resque
|
140
|
+
[2]: https://github.com/han/stalker
|
141
|
+
[3]: https://github.com/tobi/delayed_job
|
142
|
+
[4]: https://github.com/igrigorik/em-http-request
|
143
|
+
[5]: https://github.com/igrigorik/em-websocket
|
144
|
+
[6]: http://redis.io
|
@@ -17,6 +17,7 @@ JR.config[:log_job_processing] = true
|
|
17
17
|
JR.config[:always_use_specified_node] = false #will send job to another node if specified node is not available
|
18
18
|
JR.config[:remove_done_jobs] = true
|
19
19
|
JR.config[:remove_cancelled_jobs] = true
|
20
|
+
JR.config[:remove_failed_jobs] = false
|
20
21
|
|
21
22
|
JR.config[:redis_host] = 'localhost'
|
22
23
|
JR.config[:redis_port] = 6379
|
data/lib/job_reactor/node.rb
CHANGED
@@ -54,11 +54,7 @@ module JobReactor
|
|
54
54
|
def schedule(hash)
|
55
55
|
EM::Timer.new(hash['make_after']) do #Of course, we can start job immediately (unless it is 'after' job), but we let EM take care about it. Maybe there is another job is ready to start
|
56
56
|
self.storage.load(hash) do |hash|
|
57
|
-
|
58
|
-
do_job(job)
|
59
|
-
else
|
60
|
-
#TODO Do nothing or raise exception ????
|
61
|
-
end
|
57
|
+
do_job(JR.make(hash))
|
62
58
|
end
|
63
59
|
end
|
64
60
|
end
|
@@ -75,6 +71,7 @@ module JobReactor
|
|
75
71
|
def do_job(job)
|
76
72
|
job['run_at'] = Time.now
|
77
73
|
job['status'] = 'in progress'
|
74
|
+
job['attempt'] += 1
|
78
75
|
storage.save(job) do |job|
|
79
76
|
begin
|
80
77
|
args = job['args'].merge(JR.config[:merge_job_itself_to_args] ? {:job_itself => job.dup} : {})
|
@@ -136,10 +133,16 @@ module JobReactor
|
|
136
133
|
#Tryes again or report error
|
137
134
|
#
|
138
135
|
def complete_rescue(job)
|
139
|
-
if job['attempt'].to_i < JobReactor.config[:max_attempt]
|
136
|
+
if job['attempt'].to_i < JobReactor.config[:max_attempt]
|
140
137
|
try_again(job)
|
141
138
|
else
|
139
|
+
job['status'] = 'failed'
|
142
140
|
report_error(job) if job['on_error']
|
141
|
+
if JR.config[:remove_failed_jobs]
|
142
|
+
storage.destroy(job)
|
143
|
+
else
|
144
|
+
storage.save(job)
|
145
|
+
end
|
143
146
|
end
|
144
147
|
end
|
145
148
|
|
@@ -159,7 +162,6 @@ module JobReactor
|
|
159
162
|
# They will be rescheduled after period time.
|
160
163
|
#
|
161
164
|
def try_again(job)
|
162
|
-
job['attempt'] += 1
|
163
165
|
if job['period'] && job['period'] > 0
|
164
166
|
job['make_after'] = job['period']
|
165
167
|
else
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'redis'
|
2
|
+
module JobReactor
|
3
|
+
module RedisMonitor
|
4
|
+
|
5
|
+
ATTRS = %w(id name args last_error run_at failed_at attempt period make_after status distributor on_success on_error)
|
6
|
+
|
7
|
+
extend self
|
8
|
+
|
9
|
+
def storage
|
10
|
+
@@storage ||= Redis.new(host: JR.config[:redis_host], port: JR.config[:redis_port])
|
11
|
+
end
|
12
|
+
|
13
|
+
# Returns all job for given node.
|
14
|
+
#
|
15
|
+
def jobs_for(name, to_be_retried = false)
|
16
|
+
pattern = "*#{name}_*"
|
17
|
+
keys = storage.keys(pattern)
|
18
|
+
result = {}
|
19
|
+
keys.each do |key|
|
20
|
+
hash = self.load(key)
|
21
|
+
if to_be_retried
|
22
|
+
result.merge!(key => hash) if hash['status'] != 'complete' && hash['status'] != 'cancelled' && hash['status'] != 'failed'
|
23
|
+
else
|
24
|
+
result.merge!(key => hash)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
result
|
28
|
+
end
|
29
|
+
|
30
|
+
# Load job from storage.
|
31
|
+
#
|
32
|
+
def load(key)
|
33
|
+
hash = {}
|
34
|
+
record = storage.hmget(key, *ATTRS)
|
35
|
+
ATTRS.each_with_index do |attr, i|
|
36
|
+
hash[attr] = record[i]
|
37
|
+
end
|
38
|
+
['attempt', 'period', 'make_after'].each do |attr|
|
39
|
+
hash[attr] = hash[attr].to_i
|
40
|
+
end
|
41
|
+
hash['args'] = Marshal.load(hash['args'])
|
42
|
+
|
43
|
+
hash
|
44
|
+
end
|
45
|
+
|
46
|
+
def destroy(key)
|
47
|
+
storage.del(key)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Destroys all job for given node.
|
51
|
+
#
|
52
|
+
def destroy_all_jobs_for(name)
|
53
|
+
pattern = "*#{name}_*"
|
54
|
+
storage.del(*storage.keys(pattern))
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -60,7 +60,8 @@ module JobReactor
|
|
60
60
|
hash['id'] = id
|
61
61
|
hash['node'] = name
|
62
62
|
self.load(hash) do |hash|
|
63
|
-
if hash['status'] != 'complete' && hash['status'] != 'cancelled' && hash['
|
63
|
+
if hash['status'] != 'complete' && hash['status'] != 'cancelled' && hash['status'] != 'failed'
|
64
|
+
else
|
64
65
|
block.call(hash)
|
65
66
|
end
|
66
67
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: job_reactor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.0.
|
4
|
+
version: 0.5.0.beta4
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-06-
|
13
|
+
date: 2012-06-05 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: eventmachine
|
@@ -28,6 +28,22 @@ dependencies:
|
|
28
28
|
- - ! '>='
|
29
29
|
- !ruby/object:Gem::Version
|
30
30
|
version: '0'
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: redis
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
type: :runtime
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
31
47
|
- !ruby/object:Gem::Dependency
|
32
48
|
name: em-redis
|
33
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,6 +74,7 @@ files:
|
|
58
74
|
- lib/job_reactor/distributor.rb
|
59
75
|
- lib/job_reactor/logger.rb
|
60
76
|
- lib/job_reactor/storages/memory_storage.rb
|
77
|
+
- lib/job_reactor/storages/redis_monitor.rb
|
61
78
|
- lib/job_reactor/storages/redis_storage.rb
|
62
79
|
- lib/job_reactor/job_reactor/storages.rb
|
63
80
|
- lib/job_reactor/job_reactor/config.rb
|