riaq 0.0.1
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.
- checksums.yaml +15 -0
- data/LICENSE +19 -0
- data/README.md +91 -0
- data/Rakefile +5 -0
- data/lib/riaq.rb +92 -0
- data/riaq.gemspec +22 -0
- data/test/riaq_test.rb +85 -0
- metadata +79 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZWI0ODkwNGRhMWFjNjRhNzM3OGJiMTRjOWNjZGZlM2FhYTY2NTVkYg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
OWQ2MjZiYTcwZWEyMjk2OGY3NmM2NjlhZGNmMTU1M2ZhZTYzZmUyNg==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
M2YwNjgwMDc3NDM5NWUxOGNhZWQ3ODU3NGUwMWE5OTFkZTQyZGFkMmRkYTNl
|
10
|
+
NmExMDM4NmI3YTJiMzE0OWU1OGZmYzZiYThlOTU4YmZmYmZiZjg5MjA3YjAx
|
11
|
+
ZGZhNjYyYjgxYTNjNmQxNzZkNmRjNTc4YjdjOGZkNTkxM2U5Zjc=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MGE3YWY4OGQyMGEyNzg4MTYzYTc3OWZkNGQwNWIxNjEzYTA5ZmQ2NmQ4MGQx
|
14
|
+
N2E2MTg4YjA2OGM5OGUwZmIwY2VmODJhZGYzMTE2NGJiNjFmODM5YzNmOTdl
|
15
|
+
YjJkMGMzZWNjMmY4YjVlODI5M2MzN2MwNjNkYjk0MTFjYWM0YmM=
|
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2014 Matías Flores
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# Riaq
|
2
|
+
|
3
|
+
Experimental attempt of providing Riak based queues and workers,
|
4
|
+
heavily inspired by [Ost](https://github.com/soveran/ost).
|
5
|
+
|
6
|
+
Due to Riak's distributed capabilities and lack of atomic operations,
|
7
|
+
as soon as you launch more than one worker there's no guarantee that
|
8
|
+
each item added to the queue will be processed just once. If you can't
|
9
|
+
live with this limitation, then this tool is not for you.
|
10
|
+
|
11
|
+
## Description
|
12
|
+
|
13
|
+
*Riaq* makes it easy to enqueue object ids and process them with
|
14
|
+
workers.
|
15
|
+
|
16
|
+
Say you want to process video uploads. In your application you will
|
17
|
+
have something like this:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
Riaq[:videos_to_process].push(@video.id)
|
21
|
+
```
|
22
|
+
|
23
|
+
Then, you will have a worker that will look like this:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
require "riaq"
|
27
|
+
|
28
|
+
Riaq[:videos_to_process].each do |id|
|
29
|
+
# Do something with it!
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
## Usage
|
34
|
+
|
35
|
+
*Riaq* connects to Riak automatically with the default options.
|
36
|
+
|
37
|
+
You can customize the connection by calling `connect`.
|
38
|
+
|
39
|
+
Then you only need to refer to a queue for it to pop into existence:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
Riaq[:rss_feeds] << @feed.id
|
43
|
+
```
|
44
|
+
|
45
|
+
A worker is a Ruby file with this basic code:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
require "riaq"
|
49
|
+
|
50
|
+
Riaq[:rss_feeds].each do |id|
|
51
|
+
# ...
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
It will pop items from the queue as soon as they become available.
|
56
|
+
|
57
|
+
Note that in these examples we are pushing numbers to the queue. As
|
58
|
+
we have unlimited queues, each queue should be specialized and the
|
59
|
+
workers must be smart enough to know what to do with the numbers they
|
60
|
+
pop.
|
61
|
+
|
62
|
+
### Available methods
|
63
|
+
|
64
|
+
`Riaq.connect`: configure the connection to Riak. It accepts
|
65
|
+
the same options as [the Riak Ruby client](https://github.com/basho/riak-ruby-client).
|
66
|
+
|
67
|
+
`Riaq.stop`: halt processing for all queues.
|
68
|
+
|
69
|
+
`Riaq[:example].push item`, `Riaq[:some_queue] << item`: add `item` to
|
70
|
+
the `:example` queue.
|
71
|
+
|
72
|
+
`Riaq[:example].each { |item| ... }`: consume `item` from the `:example` queue.
|
73
|
+
|
74
|
+
`Riaq[:example].stop`: halt processing for the `example` queue.
|
75
|
+
|
76
|
+
## Priorities
|
77
|
+
|
78
|
+
There's no concept of priorities, as each queue is specialized and you
|
79
|
+
can create as many as you want. For example, nothing prevents the
|
80
|
+
creation of the `:example_high_priority` or the
|
81
|
+
`:example_low_priority` queues.
|
82
|
+
|
83
|
+
## Installation
|
84
|
+
|
85
|
+
$ gem install riaq
|
86
|
+
|
87
|
+
## License
|
88
|
+
|
89
|
+
Distributed under the terms of the MIT license.
|
90
|
+
See bundled [LICENSE](https://github.com/matflores/riaq/blob/master/LICENSE)
|
91
|
+
file for more info.
|
data/Rakefile
ADDED
data/lib/riaq.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
require "riak"
|
2
|
+
|
3
|
+
module Riaq
|
4
|
+
PENDING = 0
|
5
|
+
PROCESSING = 1
|
6
|
+
|
7
|
+
class Queue
|
8
|
+
attr :bucket
|
9
|
+
|
10
|
+
def initialize(name)
|
11
|
+
@bucket = riak.bucket("riaq:#{name}")
|
12
|
+
end
|
13
|
+
|
14
|
+
def push(value)
|
15
|
+
item = @bucket.new(Time.now.to_f)
|
16
|
+
item.content_type = "text/plain"
|
17
|
+
item.data = value
|
18
|
+
item.indexes = { status_int: PENDING }
|
19
|
+
item.store
|
20
|
+
end
|
21
|
+
|
22
|
+
def each(&block)
|
23
|
+
@stopping = false
|
24
|
+
|
25
|
+
loop do
|
26
|
+
break if @stopping
|
27
|
+
|
28
|
+
key = bucket.get_index("status_int", PENDING, max_results: 1).first
|
29
|
+
|
30
|
+
next unless key
|
31
|
+
|
32
|
+
item = @bucket.get(key)
|
33
|
+
item.indexes = { status_int: PROCESSING }
|
34
|
+
item.store
|
35
|
+
|
36
|
+
block.call(item.data)
|
37
|
+
|
38
|
+
item.delete
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def flush
|
43
|
+
bucket.get_index("$bucket", @bucket.name).each do |key|
|
44
|
+
@bucket.delete(key)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def stop
|
49
|
+
@stopping = true
|
50
|
+
end
|
51
|
+
|
52
|
+
def items
|
53
|
+
Riak::MapReduce.new(riak).index(@bucket.name, "status_int", PENDING).map("Riak.mapValues", keep: true).run
|
54
|
+
end
|
55
|
+
|
56
|
+
def size
|
57
|
+
bucket.get_index("status_int", PENDING).size
|
58
|
+
end
|
59
|
+
|
60
|
+
def empty?
|
61
|
+
size == 0
|
62
|
+
end
|
63
|
+
|
64
|
+
alias << push
|
65
|
+
|
66
|
+
def riak
|
67
|
+
@riak ||= Riak::Client.new(Riaq.options)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
@queues = Hash.new do |hash, key|
|
72
|
+
hash[key] = Queue.new(key)
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.[](queue)
|
76
|
+
@queues[queue]
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.stop
|
80
|
+
@queues.each { |_, queue| queue.stop }
|
81
|
+
end
|
82
|
+
|
83
|
+
@options = nil
|
84
|
+
|
85
|
+
def self.connect(options = {})
|
86
|
+
@options = options
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.options
|
90
|
+
@options || {}
|
91
|
+
end
|
92
|
+
end
|
data/riaq.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "riaq"
|
3
|
+
s.version = "0.0.1"
|
4
|
+
s.summary = "Riak based queues and workers, inspired by Ost."
|
5
|
+
s.description = "Riaq lets you manage queues and workers with Riak."
|
6
|
+
s.authors = ["Matías Flores"]
|
7
|
+
s.email = ["flores.matias@gmail.com"]
|
8
|
+
s.homepage = "http://github.com/soveran/ost"
|
9
|
+
s.license = "MIT"
|
10
|
+
|
11
|
+
s.files = Dir[
|
12
|
+
"LICENSE",
|
13
|
+
"README.md",
|
14
|
+
"Rakefile",
|
15
|
+
"lib/**/*.rb",
|
16
|
+
"*.gemspec",
|
17
|
+
"test/*.*"
|
18
|
+
]
|
19
|
+
|
20
|
+
s.add_dependency "riak-client", "~> 1.4.3"
|
21
|
+
s.add_development_dependency "protest", "~> 0.5.1"
|
22
|
+
end
|
data/test/riaq_test.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
require "protest"
|
2
|
+
require_relative "../lib/riaq"
|
3
|
+
|
4
|
+
Protest.context "Riaq" do
|
5
|
+
setup do
|
6
|
+
Riaq[:test].flush
|
7
|
+
end
|
8
|
+
|
9
|
+
test "access queued items" do
|
10
|
+
push "1"
|
11
|
+
|
12
|
+
assert_equal ["1"], Riaq[:test].items
|
13
|
+
end
|
14
|
+
|
15
|
+
test "query the number of queued items" do
|
16
|
+
push "1"
|
17
|
+
|
18
|
+
assert_equal 1, Riaq[:test].size
|
19
|
+
end
|
20
|
+
|
21
|
+
test "check queue emptiness" do
|
22
|
+
assert Riaq[:test].empty?
|
23
|
+
|
24
|
+
push "1"
|
25
|
+
|
26
|
+
assert !Riaq[:test].empty?
|
27
|
+
end
|
28
|
+
|
29
|
+
test "process items from the queue in order" do |redis|
|
30
|
+
%w(1 2 3).each { |i| push i }
|
31
|
+
|
32
|
+
results = []
|
33
|
+
|
34
|
+
process do |item|
|
35
|
+
results << item
|
36
|
+
end
|
37
|
+
|
38
|
+
assert Riaq[:test].empty?
|
39
|
+
assert_equal ["1", "2", "3"], results
|
40
|
+
end
|
41
|
+
|
42
|
+
test "halt processing a queue" do
|
43
|
+
Thread.new do
|
44
|
+
sleep 0.5
|
45
|
+
Riaq[:always_empty].stop
|
46
|
+
end
|
47
|
+
|
48
|
+
Riaq[:always_empty].each { }
|
49
|
+
|
50
|
+
assert true
|
51
|
+
end
|
52
|
+
|
53
|
+
test "halt processing all queues" do
|
54
|
+
Thread.new do
|
55
|
+
sleep 0.5
|
56
|
+
Riaq.stop
|
57
|
+
end
|
58
|
+
|
59
|
+
t1 = Thread.new { Riaq[:always_empty].each { } }
|
60
|
+
t2 = Thread.new { Riaq[:always_empty_too].each { } }
|
61
|
+
|
62
|
+
t1.join
|
63
|
+
t2.join
|
64
|
+
|
65
|
+
assert true
|
66
|
+
end
|
67
|
+
|
68
|
+
def push(id)
|
69
|
+
Riaq[:test].push(id)
|
70
|
+
end
|
71
|
+
|
72
|
+
def process(&job)
|
73
|
+
thread = Thread.new do
|
74
|
+
Riaq[:test].each do |item|
|
75
|
+
begin
|
76
|
+
yield(item)
|
77
|
+
ensure
|
78
|
+
thread.kill if Riaq[:test].empty?
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
thread.join
|
84
|
+
end
|
85
|
+
end
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: riaq
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Matías Flores
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-02-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: riak-client
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.4.3
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.4.3
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: protest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.5.1
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.5.1
|
41
|
+
description: Riaq lets you manage queues and workers with Riak.
|
42
|
+
email:
|
43
|
+
- flores.matias@gmail.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- LICENSE
|
49
|
+
- README.md
|
50
|
+
- Rakefile
|
51
|
+
- lib/riaq.rb
|
52
|
+
- riaq.gemspec
|
53
|
+
- test/riaq_test.rb
|
54
|
+
homepage: http://github.com/soveran/ost
|
55
|
+
licenses:
|
56
|
+
- MIT
|
57
|
+
metadata: {}
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ! '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
requirements: []
|
73
|
+
rubyforge_project:
|
74
|
+
rubygems_version: 2.0.3
|
75
|
+
signing_key:
|
76
|
+
specification_version: 4
|
77
|
+
summary: Riak based queues and workers, inspired by Ost.
|
78
|
+
test_files: []
|
79
|
+
has_rdoc:
|