disc 0.0.21 → 0.0.22
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +21 -0
- data/README.md +5 -5
- data/lib/disc/version.rb +1 -1
- data/lib/disc.rb +17 -4
- data/test/disc_test.rb +98 -54
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c6bf616dea2ead6c544788565f1b487ddaedeffa
|
4
|
+
data.tar.gz: 191da0a289ac1ec6b1b60d76d547e996b7e56083
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 83c6e1a7cf0aaba55e156097a8f02f772227854fb93fcca59d10acd15df8dff8b1d4dc1582af091b1e926f2d5b011f2d122a64eb53223f2d841fbe87ea45485f
|
7
|
+
data.tar.gz: 212a4df34ad33ad7865e934e46964517aa77a6127d9545653ee148f9cdfcbfa3bebad9903577e35163939d9888df6e6a1cf2428022224b38319923ea1858dddf
|
data/.travis.yml
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.2
|
4
|
+
sudo: false
|
5
|
+
cache:
|
6
|
+
bundler: false
|
7
|
+
directories:
|
8
|
+
- disque
|
9
|
+
- gems
|
10
|
+
before_install:
|
11
|
+
- test -d disque/.git || git clone -n https://github.com/antirez/disque.git
|
12
|
+
- cd disque && git fetch origin && git checkout -f master && make && cd ..
|
13
|
+
install:
|
14
|
+
- export GEM_HOME=$PWD/gems/$RUBY_VERSION
|
15
|
+
- export GEM_PATH=$GEM_HOME:$GEM_PATH
|
16
|
+
- export PATH=$GEM_HOME/bin:$PWD/disque/src:$PATH
|
17
|
+
- mkdir -p $GEM_HOME
|
18
|
+
- which dep || gem install dep
|
19
|
+
- dep install
|
20
|
+
before_script: disque-server --daemonize yes
|
21
|
+
script: make test
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Disc
|
1
|
+
# Disc [![Build Status](https://travis-ci.org/pote/disc.svg?branch=master)](https://travis-ci.org/pote/disc)
|
2
2
|
|
3
3
|
Disc fills the gap between your Ruby service objects and [antirez](http://antirez.com/)'s wonderful [Disque](https://github.com/antirez/disque) backend.
|
4
4
|
|
@@ -58,10 +58,10 @@ Disc fills the gap between your Ruby service objects and [antirez](http://antire
|
|
58
58
|
```bash
|
59
59
|
$ QUEUES=urgent,default disc -r ./disc_init.rb
|
60
60
|
```
|
61
|
-
|
61
|
+
|
62
62
|
## Notes about Jobs
|
63
63
|
|
64
|
-
Jobs are fairly
|
64
|
+
Jobs are fairly straightforward Ruby classes, internally Disc serializes them to MessagePack so they can be stored in Disque, this has a few implications:
|
65
65
|
|
66
66
|
* Don't enqueue complex objects! Instead of `user`, enqueue `user.id`!
|
67
67
|
* If your job takes multiple arguments, you'll want to pass all those arguments in the first parameter of `#enqueue` as an array.
|
@@ -72,7 +72,7 @@ Example:
|
|
72
72
|
class ComplexJob
|
73
73
|
include Disc::Job
|
74
74
|
disc queue: 'urgent'
|
75
|
-
|
75
|
+
|
76
76
|
def perform(first_parameter, second_parameter)
|
77
77
|
# do things...
|
78
78
|
end
|
@@ -191,7 +191,7 @@ more information.
|
|
191
191
|
## Acknowledgements
|
192
192
|
|
193
193
|
* To [@foca](https://github.com/foca) for helping me ship a quality thing and putting up with my constant whining.
|
194
|
-
* To [@antirez](https://github
|
194
|
+
* To [@antirez](https://github.com/antirez) for Redis, Disque, and his refreshing way of programming wonderful tools.
|
195
195
|
* To [@soveran](https://github.com/soveran) for pushing me to work on this and publishing gems that keep me enjoying ruby.
|
196
196
|
* To [all contributors](https://github.com/pote/disc/graphs/contributors)
|
197
197
|
|
data/lib/disc/version.rb
CHANGED
data/lib/disc.rb
CHANGED
@@ -28,6 +28,14 @@ class Disc
|
|
28
28
|
@disque_timeout = timeout
|
29
29
|
end
|
30
30
|
|
31
|
+
def self.default_queue
|
32
|
+
@default_queue ||= 'default'
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.default_queue=(queue)
|
36
|
+
@default_queue = queue
|
37
|
+
end
|
38
|
+
|
31
39
|
def self.on_error(exception, job)
|
32
40
|
$stderr.puts exception
|
33
41
|
end
|
@@ -101,7 +109,8 @@ class Disc
|
|
101
109
|
@disque = disque
|
102
110
|
end
|
103
111
|
|
104
|
-
def disc(
|
112
|
+
def disc(queue: nil, **options)
|
113
|
+
@queue = queue
|
105
114
|
@disc_options = options
|
106
115
|
end
|
107
116
|
|
@@ -110,10 +119,14 @@ class Disc
|
|
110
119
|
end
|
111
120
|
|
112
121
|
def queue
|
113
|
-
|
122
|
+
@queue || Disc.default_queue
|
114
123
|
end
|
115
124
|
|
116
|
-
def enqueue(args = [], at: nil, queue: nil)
|
125
|
+
def enqueue(args = [], at: nil, queue: nil, **options)
|
126
|
+
options = disc_options.merge(options).tap do |opt|
|
127
|
+
opt[:delay] = at.to_time.to_i - DateTime.now.to_time.to_i unless at.nil?
|
128
|
+
end
|
129
|
+
|
117
130
|
disque.push(
|
118
131
|
queue || self.queue,
|
119
132
|
{
|
@@ -121,7 +134,7 @@ class Disc
|
|
121
134
|
arguments: Array(args)
|
122
135
|
}.to_msgpack,
|
123
136
|
Disc.disque_timeout,
|
124
|
-
|
137
|
+
options
|
125
138
|
)
|
126
139
|
end
|
127
140
|
end
|
data/test/disc_test.rb
CHANGED
@@ -2,6 +2,7 @@ require 'cutest'
|
|
2
2
|
require 'disc'
|
3
3
|
require 'msgpack'
|
4
4
|
require 'pty'
|
5
|
+
require 'timeout'
|
5
6
|
|
6
7
|
require_relative '../examples/echoer'
|
7
8
|
# class Echoer
|
@@ -30,10 +31,29 @@ require_relative '../examples/failer'
|
|
30
31
|
# end
|
31
32
|
|
32
33
|
prepare do
|
34
|
+
Disc.disque_timeout = 1 # 1ms so we don't wait at all.
|
33
35
|
Disc.disque.call('DEBUG', 'FLUSHALL')
|
34
36
|
end
|
35
37
|
|
36
38
|
scope do
|
39
|
+
# Runs a given command, yielding the stdout (as an IO) and the PID (a String).
|
40
|
+
# Makes sure the process finishes after the block runs.
|
41
|
+
def run(command)
|
42
|
+
out, _, pid = PTY.spawn(command)
|
43
|
+
yield out, pid
|
44
|
+
ensure
|
45
|
+
Process.kill("KILL", pid)
|
46
|
+
sleep 0.1 # Make sure we give it time to finish.
|
47
|
+
end
|
48
|
+
|
49
|
+
# Checks whether a process is running.
|
50
|
+
def is_running?(pid)
|
51
|
+
Process.getpgid(pid)
|
52
|
+
true
|
53
|
+
rescue Errno::ESRCH
|
54
|
+
false
|
55
|
+
end
|
56
|
+
|
37
57
|
test 'jobs are enqueued to the correct Disque queue with appropriate parameters and class' do
|
38
58
|
jobid = Echoer.enqueue(['one argument', { random: 'data' }, 3])
|
39
59
|
|
@@ -59,16 +79,16 @@ scope do
|
|
59
79
|
end
|
60
80
|
|
61
81
|
test 'enqueue at timestamp behaves properly' do
|
62
|
-
jobid = Echoer.enqueue(['one argument', { random: 'data' }, 3], at: Time.now +
|
82
|
+
jobid = Echoer.enqueue(['one argument', { random: 'data' }, 3], at: Time.now + 1)
|
63
83
|
|
64
84
|
jobs = Array(Disc.disque.fetch(from: ['test'], timeout: Disc.disque_timeout, count: 1))
|
65
85
|
assert jobs.empty?
|
66
86
|
|
67
|
-
sleep
|
87
|
+
sleep 0.5
|
68
88
|
jobs = Array(Disc.disque.fetch(from: ['test'], timeout: Disc.disque_timeout, count: 1))
|
69
89
|
assert jobs.empty?
|
70
90
|
|
71
|
-
sleep
|
91
|
+
sleep 0.5
|
72
92
|
jobs = Array(Disc.disque.fetch(from: ['test'], timeout: Disc.disque_timeout, count: 1))
|
73
93
|
assert jobs.any?
|
74
94
|
assert_equal 1, jobs.size
|
@@ -85,68 +105,92 @@ scope do
|
|
85
105
|
end
|
86
106
|
|
87
107
|
test 'jobs are executed' do
|
88
|
-
|
89
|
-
Echoer.enqueue(['one argument', { random: 'data' }, 3])
|
90
|
-
|
91
|
-
cout, _, pid = PTY.spawn(
|
92
|
-
'QUEUES=test,default ruby -Ilib bin/disc -r ./examples/echoer'
|
93
|
-
)
|
94
|
-
sleep 0.5
|
108
|
+
Echoer.enqueue(['one argument', { random: 'data' }, 3])
|
95
109
|
|
110
|
+
run('QUEUES=test ruby -Ilib bin/disc -r ./examples/echoer') do |cout, pid|
|
111
|
+
output = Timeout.timeout(1) { cout.take(3) }
|
96
112
|
jobs = Disc.disque.fetch(from: ['test'], timeout: Disc.disque_timeout, count: 1)
|
97
113
|
assert jobs.nil?
|
98
|
-
|
99
|
-
matched = false
|
100
|
-
counter = 0
|
101
|
-
while !matched && counter < 3
|
102
|
-
counter += 1
|
103
|
-
matched = cout.gets.match(/First: one argument, Second: {"random"=>"data"}, Third: 3/)
|
104
|
-
end
|
105
|
-
|
106
|
-
assert matched
|
107
|
-
ensure
|
108
|
-
Process.kill("KILL", pid)
|
114
|
+
assert output.grep(/First: one argument, Second: {"random"=>"data"}, Third: 3/).any?
|
109
115
|
end
|
110
116
|
end
|
111
117
|
|
112
118
|
test 'Disc.on_error will catch unhandled exceptions and keep disc alive' do
|
113
|
-
|
114
|
-
Failer.enqueue('this can only end positively')
|
115
|
-
|
116
|
-
cout, _, pid = PTY.spawn(
|
117
|
-
'QUEUES=test ruby -Ilib bin/disc -r ./examples/failer'
|
118
|
-
)
|
119
|
-
sleep 0.5
|
119
|
+
Failer.enqueue('this can only end positively')
|
120
120
|
|
121
|
+
run('QUEUES=test ruby -Ilib bin/disc -r ./examples/failer') do |cout, pid|
|
122
|
+
output = Timeout.timeout(1) { cout.take(5) }
|
121
123
|
jobs = Disc.disque.fetch(from: ['test'], timeout: Disc.disque_timeout, count: 1)
|
122
124
|
assert jobs.nil?
|
123
125
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
}
|
130
|
-
|
131
|
-
while tasks.values.include?(false) && counter < 5
|
132
|
-
counter += 1
|
133
|
-
output = cout.gets
|
134
|
-
|
135
|
-
tasks[:reported_error] = true if output.match(/<insert error reporting here>/)
|
136
|
-
tasks[:printed_message] = true if output.match(/this can only end positively/)
|
137
|
-
tasks[:printed_job] = true if output.match(/Failer/)
|
138
|
-
end
|
139
|
-
|
140
|
-
assert !tasks.values.include?(false)
|
141
|
-
|
142
|
-
begin
|
143
|
-
Process.getpgid(pid)
|
144
|
-
assert true
|
145
|
-
rescue Errno::ESRCH
|
146
|
-
assert false
|
147
|
-
end
|
148
|
-
ensure
|
149
|
-
Process.kill("KILL", pid)
|
126
|
+
assert output.grep(/<insert error reporting here>/).any?
|
127
|
+
assert output.grep(/this can only end positively/).any?
|
128
|
+
assert output.grep(/Failer/).any?
|
129
|
+
|
130
|
+
assert is_running?(pid)
|
150
131
|
end
|
151
132
|
end
|
133
|
+
|
134
|
+
test 'enqueue supports replicate' do
|
135
|
+
error = Echoer.enqueue(['one argument', { random: 'data' }, 3], replicate: 100) rescue $!
|
136
|
+
|
137
|
+
assert_equal RuntimeError, error.class
|
138
|
+
assert_equal "NOREPL Not enough reachable nodes for the requested replication level", error.message
|
139
|
+
end
|
140
|
+
|
141
|
+
test 'enqueue supports delay' do
|
142
|
+
jobid = Echoer.enqueue(['one argument', { random: 'data' }, 3], delay: 2)
|
143
|
+
|
144
|
+
jobs = Array(Disc.disque.fetch(from: ['test'], timeout: Disc.disque_timeout, count: 1))
|
145
|
+
assert jobs.empty?
|
146
|
+
|
147
|
+
sleep 1
|
148
|
+
jobs = Array(Disc.disque.fetch(from: ['test'], timeout: Disc.disque_timeout, count: 1))
|
149
|
+
assert jobs.empty?
|
150
|
+
|
151
|
+
sleep 2
|
152
|
+
jobs = Array(Disc.disque.fetch(from: ['test'], timeout: Disc.disque_timeout, count: 1))
|
153
|
+
assert jobs.any?
|
154
|
+
assert_equal 1, jobs.size
|
155
|
+
end
|
156
|
+
|
157
|
+
test 'enqueue supports retry' do
|
158
|
+
jobid = Echoer.enqueue(['one argument', { random: 'data' }, 3], retry: 1)
|
159
|
+
|
160
|
+
jobs = Array(Disc.disque.fetch(from: ['test'], timeout: Disc.disque_timeout, count: 1))
|
161
|
+
assert jobs.any?
|
162
|
+
assert_equal 1, jobs.size
|
163
|
+
|
164
|
+
sleep 1.5
|
165
|
+
jobs = Array(Disc.disque.fetch(from: ['test'], timeout: Disc.disque_timeout, count: 1))
|
166
|
+
assert jobs.any?
|
167
|
+
assert_equal 1, jobs.size
|
168
|
+
end
|
169
|
+
|
170
|
+
test 'enqueue supports ttl' do
|
171
|
+
jobid = Echoer.enqueue(['one argument', { random: 'data' }, 3], ttl: 1)
|
172
|
+
|
173
|
+
sleep 1.5
|
174
|
+
jobs = Array(Disc.disque.fetch(from: ['test'], timeout: Disc.disque_timeout, count: 1))
|
175
|
+
assert jobs.empty?
|
176
|
+
end
|
177
|
+
|
178
|
+
test 'enqueue supports maxlen' do
|
179
|
+
Echoer.enqueue(['one argument', { random: 'data' }, 3], maxlen: 1)
|
180
|
+
# disque off by-one bug? see: https://github.com/antirez/disque/issues/109
|
181
|
+
Echoer.enqueue(['one argument', { random: 'data' }, 3], maxlen: 1)
|
182
|
+
error = Echoer.enqueue(['one argument', { random: 'data' }, 3], maxlen: 1) rescue $!
|
183
|
+
|
184
|
+
assert_equal RuntimeError, error.class
|
185
|
+
assert_equal "MAXLEN Queue is already longer than the specified MAXLEN count", error.message
|
186
|
+
end
|
187
|
+
|
188
|
+
test 'enqueue supports async' do
|
189
|
+
jobid = Echoer.enqueue(['one argument', { random: 'data' }, 3], async: true)
|
190
|
+
|
191
|
+
sleep 1 # async is too fast to reliably assert an empty queue, let's wait instead
|
192
|
+
jobs = Array(Disc.disque.fetch(from: ['test'], timeout: Disc.disque_timeout, count: 1))
|
193
|
+
assert jobs.any?
|
194
|
+
assert_equal 1, jobs.size
|
195
|
+
end
|
152
196
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: disc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.22
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- pote
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-08-
|
11
|
+
date: 2015-08-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: disque
|
@@ -63,6 +63,7 @@ files:
|
|
63
63
|
- ".env.sample"
|
64
64
|
- ".gems"
|
65
65
|
- ".gitignore"
|
66
|
+
- ".travis.yml"
|
66
67
|
- 13Floor-circulo-1.png
|
67
68
|
- CONTRIBUTING.md
|
68
69
|
- LICENSE
|