riaq 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (8) hide show
  1. checksums.yaml +15 -0
  2. data/LICENSE +19 -0
  3. data/README.md +91 -0
  4. data/Rakefile +5 -0
  5. data/lib/riaq.rb +92 -0
  6. data/riaq.gemspec +22 -0
  7. data/test/riaq_test.rb +85 -0
  8. metadata +79 -0
@@ -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.
@@ -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.
@@ -0,0 +1,5 @@
1
+ task :test do
2
+ Dir["test/*.rb"].each { |file| load file }
3
+ end
4
+
5
+ task :default => :test
@@ -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
@@ -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
@@ -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: