queuel 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.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.irbrc ADDED
@@ -0,0 +1,2 @@
1
+ $:<< "./lib"
2
+ require 'queuel'
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/.rvmrc ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # This is an RVM Project .rvmrc file, used to automatically load the ruby
4
+ # development environment upon cd'ing into the directory
5
+
6
+ # First we specify our desired <ruby>[@<gemset>], the @gemset name is optional,
7
+ # Only full ruby name is supported here, for short names use:
8
+ # echo "rvm use 1.9.3" > .rvmrc
9
+ environment_id="ruby-1.9.3-p392@queuel"
10
+
11
+ # Uncomment the following lines if you want to verify rvm version per project
12
+ # rvmrc_rvm_version="1.20.4 (stable)" # 1.10.1 seams as a safe start
13
+ # eval "$(echo ${rvm_version}.${rvmrc_rvm_version} | awk -F. '{print "[[ "$1*65536+$2*256+$3" -ge "$4*65536+$5*256+$6" ]]"}' )" || {
14
+ # echo "This .rvmrc file requires at least RVM ${rvmrc_rvm_version}, aborting loading."
15
+ # return 1
16
+ # }
17
+
18
+ # First we attempt to load the desired environment directly from the environment
19
+ # file. This is very fast and efficient compared to running through the entire
20
+ # CLI and selector. If you want feedback on which environment was used then
21
+ # insert the word 'use' after --create as this triggers verbose mode.
22
+ if [[ -d "${rvm_path:-$HOME/.rvm}/environments"
23
+ && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
24
+ then
25
+ \. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
26
+ for __hook in "${rvm_path:-$HOME/.rvm}/hooks/after_use"*
27
+ do
28
+ if [[ -f "${__hook}" && -x "${__hook}" && -s "${__hook}" ]]
29
+ then \. "${__hook}" || true
30
+ fi
31
+ done
32
+ unset __hook
33
+ if (( ${rvm_use_flag:=1} >= 2 )) # display only when forced
34
+ then
35
+ if [[ $- == *i* ]] # check for interactive shells
36
+ then echo "Using: \E[32m$GEM_HOME\E[0m" # show the user the ruby and gemset they are using in green
37
+ else echo "Using: $GEM_HOME" # don't use colors in non-interactive shells
38
+ fi
39
+ fi
40
+ else
41
+ # If the environment file has not yet been created, use the RVM CLI to select.
42
+ rvm --create "$environment_id" || {
43
+ echo "Failed to create RVM environment '${environment_id}'."
44
+ return 1
45
+ }
46
+ fi
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 1.9.2
5
+ - jruby-19mode
6
+ - rbx-19mode
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in queuel.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Jon Phenow
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # Queuel
2
+ [![Build Status](https://travis-ci.org/sportngin/queuel.png?branch=master)](https://travis-ci.org/sportngin/queuel)
3
+
4
+ Queuel is a kewl, lite wrapper around Queue interfaces. Currently it implements:
5
+
6
+ * IronMQ
7
+ * Null pattern
8
+
9
+ Each of these should reliably implement:
10
+
11
+ * `push`
12
+ * `pop`
13
+ * `receive`
14
+
15
+ Along with some further conveniences.
16
+
17
+ ## Installation
18
+
19
+ Add this line to your application's Gemfile as well as the proper Gem for
20
+ your queuing:
21
+
22
+ ```ruby
23
+ gem 'iron_mq'
24
+ # IronMQ recommends `gem "typhoeus"` as well for some speed benefits
25
+ gem 'queuel'
26
+ ```
27
+
28
+ And then execute:
29
+
30
+ $ bundle
31
+
32
+ You will then want to configure:
33
+
34
+ ```ruby
35
+ Queuel.configure do
36
+ # Optional, but a queue must be selected before running put/pop/receive
37
+ default_queue :venues
38
+
39
+ # requirement depends on your Queue
40
+ credentials token: 'asdufasdf8a7sd8fa7sdf', project_id: 'project_id'
41
+
42
+ # currently only [:iron_mq, :null] available
43
+ engine :iron_mq
44
+ end
45
+ ```
46
+
47
+ ## Usage
48
+
49
+ ### General Queue API
50
+
51
+ ```ruby
52
+ # Using default Queue
53
+ Queuel.pop
54
+ Queuel.push "My message to you"
55
+ Queuel.receive do |message|
56
+ puts "I received #{message.body}" # NOTE the message interface may change, this is currently not wrapped by the gem
57
+ end
58
+
59
+ # With the non-default queue
60
+ Queuel.with("officials").pop
61
+ Queuel.with("officials").push "My message to you"
62
+ Queuel.with("officials").receive do |message|
63
+ puts "I received #{message.body}" # NOTE the message interface may change, this is currently not wrapped by the gem
64
+ end
65
+
66
+ # Timeout the receiving
67
+ Queuel.receive poll_timeout: 60 do |message|
68
+ puts "I received #{message.body}" # NOTE the message interface may change, this is currently not wrapped by the gem
69
+ end
70
+
71
+ # Don't receive more than 10 nil messages
72
+ Queuel.receive max_consecutive_fails: 10 do |message|
73
+ puts "I received #{message.body}" # NOTE the message interface may change, this is currently not wrapped by the gem
74
+ end
75
+
76
+ # Break on nil
77
+ Queuel.receive break_if_nil: true do |message|
78
+ puts "I received #{message.body}" # NOTE the message interface may change, this is currently not wrapped by the gem
79
+ end
80
+ ```
81
+
82
+ ### The message
83
+
84
+ ```ruby
85
+ message.id # => ID of the message
86
+ message.body # => Message body
87
+ message.delete # => Delete the message
88
+ ```
89
+
90
+ ## TODO
91
+
92
+ * Implement AMQP
93
+ * Configureable exponential back-off on `receive`
94
+
95
+ ## Contributing
96
+
97
+ 1. Fork it
98
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
99
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
100
+ 4. Push to the branch (`git push origin my-new-feature`)
101
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/lib/queuel.rb ADDED
@@ -0,0 +1,68 @@
1
+ require "queuel/version"
2
+ require "forwardable"
3
+ require "queuel/null/message"
4
+ require "queuel/null/engine"
5
+ require "queuel/null/poller"
6
+ require "queuel/null/queue"
7
+ require "queuel/iron_mq/message"
8
+ require "queuel/iron_mq/engine"
9
+ require "queuel/iron_mq/poller"
10
+ require "queuel/iron_mq/queue"
11
+ require "queuel/client"
12
+
13
+ module Queuel
14
+ class << self
15
+ extend Forwardable
16
+ def_delegators :client, :push, :pop, :receive, :with
17
+ def_delegators :config, :credentials, :default_queue
18
+ alias << pop
19
+ end
20
+
21
+ def self.engine
22
+ requires
23
+ Object.module_eval("::#{const_name}", __FILE__, __LINE__)
24
+ end
25
+
26
+ def self.configure(&block)
27
+ config.instance_eval &block
28
+ end
29
+
30
+ def self.config
31
+ @config ||= Configurator.new
32
+ end
33
+
34
+ def self.client
35
+ Client.new engine, credentials
36
+ end
37
+
38
+ def self.engines
39
+ {
40
+ iron_mq: { require: 'iron_mq', const: "IronMq" },
41
+ null: { const: "Null" }
42
+ }
43
+ end
44
+
45
+ def self.requires
46
+ require engines[config.engine][:require] if engines.fetch(config.engine, {})[:require]
47
+ end
48
+
49
+ def self.const_name
50
+ "Queuel::#{engines.fetch(config.engine, {}).fetch(:const, nil) || engines[:null][:const]}::Engine"
51
+ end
52
+
53
+ class Configurator
54
+ def self.param(*params)
55
+ params.each do |name|
56
+ attr_accessor name
57
+ define_method name do |*values|
58
+ value = values.first
59
+ value ? self.send("#{name}=", value) : instance_variable_get("@#{name}")
60
+ end
61
+ end
62
+ end
63
+
64
+ param :credentials
65
+ param :engine
66
+ param :default_queue
67
+ end
68
+ end
@@ -0,0 +1,37 @@
1
+ module Queuel
2
+ class Client
3
+ extend Forwardable
4
+ def_delegators :queue_connection, :push, :pop, :receive
5
+
6
+ def initialize(engine, credentials, init_queue = nil)
7
+ self.engine = engine
8
+ self.credentials = credentials
9
+ self.given_queue = init_queue
10
+ end
11
+
12
+ def with(change_queue = nil)
13
+ self.clone.tap { |client| client.given_queue = change_queue }
14
+ end
15
+
16
+ def queue
17
+ bare = (given_queue || Queuel.default_queue)
18
+ bare.to_s unless bare.nil?
19
+ end
20
+
21
+ protected
22
+ attr_accessor :given_queue
23
+
24
+ private
25
+
26
+ def queue_connection
27
+ engine_client.queue queue
28
+ end
29
+
30
+ def engine_client
31
+ @engine_client ||= engine.new credentials
32
+ end
33
+
34
+ attr_accessor :credentials
35
+ attr_accessor :engine
36
+ end
37
+ end
@@ -0,0 +1,44 @@
1
+ module Queuel
2
+ module IronMq
3
+ class Engine
4
+ IronMqMissingError = Class.new(StandardError)
5
+
6
+ def initialize(credentials = {})
7
+ self.credentials = credentials
8
+ self.memoized_queues = {}
9
+ end
10
+
11
+ def queue(which_queue)
12
+ memoized_queues[which_queue.to_s] ||= Queue.new(client, which_queue)
13
+ end
14
+
15
+ private
16
+ attr_accessor :credentials
17
+ attr_accessor :memoized_queues
18
+
19
+ def client
20
+ @client ||= client_proper.new credentials
21
+ end
22
+
23
+ def try_typhoeus
24
+ require 'typhoeus'
25
+ rescue LoadError
26
+ false
27
+ end
28
+
29
+ def client_proper
30
+ if defined?(::IronMQ::Client)
31
+ try_typhoeus
32
+ ::IronMQ::Client
33
+ else
34
+ begin
35
+ require 'iron_mq'
36
+ ::IronMQ::Client
37
+ rescue LoadError
38
+ raise(IronMqMissingError)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,43 @@
1
+ require 'forwardable'
2
+ module Queuel
3
+ module IronMq
4
+ class Message
5
+ extend Forwardable
6
+ def_delegators :message_object, :delete
7
+
8
+ def self.new_from_iron_mq_object(message_object)
9
+ allocate.tap { |instance|
10
+ instance.send :initialize_from_iron_mq_object, message_object
11
+ }
12
+ end
13
+
14
+ def initialize_from_iron_mq_object(message_object)
15
+ self.message_object = message_object
16
+ end
17
+ private :initialize_from_iron_mq_object
18
+
19
+ def initialize(id, body, queue = nil)
20
+ self.id = id
21
+ self.body = body
22
+ self.queue = queue
23
+ end
24
+
25
+ def body
26
+ @body || message_object && message_object.msg
27
+ end
28
+
29
+ [:id, :queue].each do |delegate|
30
+ define_method(delegate) do
31
+ instance_variable_get("@#{delegate}") || message_object && message_object.public_send(delegate)
32
+ end
33
+
34
+ private
35
+ attr_writer delegate
36
+ end
37
+
38
+ private
39
+ attr_accessor :message_object
40
+ attr_writer :body
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,123 @@
1
+ require 'timeout'
2
+ module Queuel
3
+ module IronMq
4
+ class Poller
5
+ def initialize(queue, options, block)
6
+ self.queue = queue
7
+ self.options = options || {}
8
+ self.block = block
9
+ self.tries = 0
10
+ self.continue_looping = true
11
+ end
12
+
13
+ def poll
14
+ choose_looper do |msg|
15
+ if msg.nil?
16
+ tried
17
+ quit_looping! if break_if_nil? || maxed_tried?
18
+ sleep(sleep_time)
19
+ else
20
+ reset_tries
21
+ block.call msg
22
+ msg.delete
23
+ end
24
+ !msg.nil?
25
+ end
26
+ end
27
+
28
+ protected
29
+ attr_accessor :tries
30
+
31
+ private
32
+ attr_accessor :queue
33
+ attr_accessor :args
34
+ attr_accessor :options
35
+ attr_accessor :block
36
+ attr_accessor :continue_looping
37
+
38
+ def choose_looper(&loop_block)
39
+ timeout? ? timeout_looper(loop_block) : looper(loop_block)
40
+ end
41
+
42
+ def timeout_looper(loop_block)
43
+ Timeout.timeout(timeout) { looper(loop_block) }
44
+ rescue Timeout::Error
45
+ false
46
+ end
47
+
48
+ def looper(loop_block)
49
+ while continue_looping? do
50
+ loop_block.call(pop_new_message)
51
+ end
52
+ end
53
+
54
+ def continue_looping?
55
+ !!continue_looping
56
+ end
57
+
58
+ def quit_looping!
59
+ self.continue_looping = false
60
+ end
61
+
62
+ def timeout
63
+ options[:poll_timeout].to_i
64
+ end
65
+
66
+ def timeout?
67
+ timeout > 0
68
+ end
69
+
70
+ def pop_new_message
71
+ queue.pop built_options
72
+ end
73
+
74
+ def start_sleep_time
75
+ 0.1
76
+ end
77
+
78
+ def sleep_time
79
+ tries < 30 ? (start_sleep_time * tries) : 3
80
+ end
81
+
82
+ def reset_tries
83
+ self.tries = 0
84
+ end
85
+
86
+ def maxed_tried?
87
+ tries >= max_fails if max_fails_given?
88
+ end
89
+
90
+ def max_fails_given?
91
+ max_fails > 0
92
+ end
93
+
94
+ def max_fails
95
+ options[:max_consecutive_fails].to_i
96
+ end
97
+
98
+ def tried
99
+ self.tries += 1
100
+ end
101
+
102
+ def break_if_nil?
103
+ !!options.fetch(:break_if_nil, false)
104
+ end
105
+
106
+ def option_keys
107
+ %w[break_if_nil poll_timeout max_consecutive_fails]
108
+ end
109
+
110
+ def my_options
111
+ options.select { |key,_| option_keys.include? key.to_s }
112
+ end
113
+
114
+ def built_options
115
+ options.merge default_args # intentional direction, force defaults
116
+ end
117
+
118
+ def default_args
119
+ { n: 1 }
120
+ end
121
+ end
122
+ end
123
+ end