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.
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: