iron 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +7 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +47 -0
- data/README.md +60 -0
- data/Rakefile +21 -0
- data/iron_mq.gemspec +31 -0
- data/lib/iron_mq.rb +5 -0
- data/lib/iron_mq/client.rb +52 -0
- data/lib/iron_mq/messages.rb +123 -0
- data/lib/iron_mq/queues.rb +169 -0
- data/lib/iron_mq/version.rb +3 -0
- data/test/long_run.rb +31 -0
- data/test/long_run_worker.rb +81 -0
- data/test/quick_run.rb +52 -0
- data/test/schedule_abt.rb +27 -0
- data/test/test_base.rb +44 -0
- data/test/test_beanstalkd.rb +222 -0
- data/test/test_bulk.rb +33 -0
- data/test/test_iron_mq.rb +356 -0
- data/test/tmp.rb +45 -0
- metadata +218 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
iron (0.0.1)
|
5
|
+
iron_core (>= 0.4.2)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
beanstalk-client (1.1.1)
|
11
|
+
concur (1.0.0)
|
12
|
+
faraday
|
13
|
+
faraday
|
14
|
+
faraday (0.8.4)
|
15
|
+
multipart-post (~> 1.1)
|
16
|
+
ffi (1.1.5)
|
17
|
+
iron_core (0.4.3)
|
18
|
+
rest (>= 2.0.2)
|
19
|
+
mime-types (1.19)
|
20
|
+
minitest (4.1.0)
|
21
|
+
multipart-post (1.1.5)
|
22
|
+
net-http-persistent (2.8)
|
23
|
+
rake (0.9.2.2)
|
24
|
+
rest (2.0.4)
|
25
|
+
net-http-persistent
|
26
|
+
rest-client (>= 0.3.0)
|
27
|
+
rest-client (1.6.7)
|
28
|
+
mime-types (>= 1.16)
|
29
|
+
test-unit (2.5.2)
|
30
|
+
typhoeus (0.4.2)
|
31
|
+
ffi (~> 1.0)
|
32
|
+
mime-types (~> 1.18)
|
33
|
+
uber_config (1.0.5)
|
34
|
+
|
35
|
+
PLATFORMS
|
36
|
+
ruby
|
37
|
+
|
38
|
+
DEPENDENCIES
|
39
|
+
beanstalk-client
|
40
|
+
concur
|
41
|
+
iron!
|
42
|
+
minitest
|
43
|
+
net-http-persistent
|
44
|
+
rake
|
45
|
+
test-unit
|
46
|
+
typhoeus
|
47
|
+
uber_config
|
data/README.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
IronMQ Ruby Client
|
2
|
+
-------------
|
3
|
+
|
4
|
+
Getting Started
|
5
|
+
==============
|
6
|
+
|
7
|
+
1\. Install the gem:
|
8
|
+
|
9
|
+
gem install iron_mq
|
10
|
+
|
11
|
+
2\. Setup your Iron.io credentials: http://dev.iron.io/articles/configuration/
|
12
|
+
|
13
|
+
3\. Create an IronMQ client object:
|
14
|
+
|
15
|
+
@ironmq = IronMQ::Client.new()
|
16
|
+
|
17
|
+
|
18
|
+
The Basics
|
19
|
+
=========
|
20
|
+
|
21
|
+
**Get a Queue object**
|
22
|
+
|
23
|
+
You can have as many queues as you want, each with their own unique set of messages.
|
24
|
+
|
25
|
+
@queue = @ironmq.queue("my_queue")
|
26
|
+
|
27
|
+
Now you can use it:
|
28
|
+
|
29
|
+
**Post** a message on the queue:
|
30
|
+
|
31
|
+
@queue.post("hello world!")
|
32
|
+
|
33
|
+
**Get** a message off the queue:
|
34
|
+
|
35
|
+
msg = @queue.get()
|
36
|
+
puts msg.body
|
37
|
+
|
38
|
+
When you pop/get a message from the queue, it will NOT be deleted. It will eventually go back onto the queue after
|
39
|
+
a timeout if you don't delete it (default timeout is 10 minutes).
|
40
|
+
|
41
|
+
**Delete** a message from the queue:
|
42
|
+
|
43
|
+
msg.delete # or @queue.delete(msg.id)
|
44
|
+
|
45
|
+
Be sure to delete a message from the queue when you're done with it.
|
46
|
+
|
47
|
+
**Poll** for messages:
|
48
|
+
|
49
|
+
@queue.poll do |msg|
|
50
|
+
puts msg.body
|
51
|
+
end
|
52
|
+
|
53
|
+
Polling will automatically delete the message at the end of the block.
|
54
|
+
|
55
|
+
Queue Information
|
56
|
+
=================
|
57
|
+
|
58
|
+
queue = @client.queue("my_queue")
|
59
|
+
puts "size: #{queue.size}"
|
60
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
require 'rake/testtask'
|
5
|
+
Rake::TestTask.new(:test) do |test|
|
6
|
+
test.libs << 'lib' << 'test'
|
7
|
+
test.pattern = 'test/**/test_*.rb'
|
8
|
+
test.verbose = true
|
9
|
+
end
|
10
|
+
|
11
|
+
task :default => :test
|
12
|
+
|
13
|
+
require 'rdoc/task'
|
14
|
+
Rake::RDocTask.new do |rdoc|
|
15
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
16
|
+
|
17
|
+
rdoc.rdoc_dir = 'doc'
|
18
|
+
rdoc.title = "iron_mq #{version}"
|
19
|
+
rdoc.rdoc_files.include('README*')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
data/iron_mq.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.expand_path('../lib/iron_mq/version', __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new do |gem|
|
4
|
+
gem.authors = ["Travis Reeder"]
|
5
|
+
gem.email = ["treeder@gmail.com"]
|
6
|
+
gem.description = "Ruby client for IronMQ by www.iron.io"
|
7
|
+
gem.summary = "Ruby client for IronMQ by www.iron.io"
|
8
|
+
gem.homepage = "https://github.com/iron-io/iron_mq_ruby"
|
9
|
+
|
10
|
+
gem.files = `git ls-files`.split($\)
|
11
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
12
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
13
|
+
gem.name = "iron"
|
14
|
+
gem.require_paths = ["lib"]
|
15
|
+
gem.version = IronMQ::VERSION
|
16
|
+
|
17
|
+
gem.required_rubygems_version = ">= 1.3.6"
|
18
|
+
gem.required_ruby_version = Gem::Requirement.new(">= 1.9")
|
19
|
+
gem.add_runtime_dependency "iron_core", ">= 0.4.2"
|
20
|
+
|
21
|
+
gem.add_development_dependency "test-unit"
|
22
|
+
gem.add_development_dependency "minitest"
|
23
|
+
gem.add_development_dependency "rake"
|
24
|
+
gem.add_development_dependency "beanstalk-client"
|
25
|
+
gem.add_development_dependency "uber_config"
|
26
|
+
gem.add_development_dependency "typhoeus"
|
27
|
+
gem.add_development_dependency "concur"
|
28
|
+
gem.add_development_dependency "net-http-persistent"
|
29
|
+
|
30
|
+
end
|
31
|
+
|
data/lib/iron_mq.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
require 'iron_core'
|
4
|
+
|
5
|
+
module IronMQ
|
6
|
+
|
7
|
+
class Client < IronCore::Client
|
8
|
+
AWS_US_EAST_HOST = 'mq-aws-us-east-1.iron.io'
|
9
|
+
|
10
|
+
attr_accessor :queue_name, :logger
|
11
|
+
|
12
|
+
def initialize(options={})
|
13
|
+
default_options = {
|
14
|
+
:scheme => 'https',
|
15
|
+
:host => IronMQ::Client::AWS_US_EAST_HOST,
|
16
|
+
:port => 443,
|
17
|
+
:api_version => 1,
|
18
|
+
:user_agent => 'iron_mq_ruby-' + IronMQ::VERSION + ' (iron_core_ruby-' + IronCore.version + ')',
|
19
|
+
:queue_name => 'default'
|
20
|
+
}
|
21
|
+
|
22
|
+
super('iron', 'mq', options, default_options, [:project_id, :token, :api_version, :queue_name])
|
23
|
+
|
24
|
+
IronCore::Logger.error 'IronMQ', "Token is not set", IronCore::Error if @token.nil?
|
25
|
+
|
26
|
+
check_id(@project_id, 'project_id')
|
27
|
+
|
28
|
+
@logger = Logger.new(STDOUT)
|
29
|
+
@logger.level = Logger::INFO
|
30
|
+
end
|
31
|
+
|
32
|
+
def headers
|
33
|
+
super.merge({'Authorization' => "OAuth #{@token}"})
|
34
|
+
end
|
35
|
+
|
36
|
+
def base_url
|
37
|
+
super + @api_version.to_s + '/'
|
38
|
+
end
|
39
|
+
|
40
|
+
def queue(name)
|
41
|
+
return Queue.new(self, {"name" => name})
|
42
|
+
end
|
43
|
+
|
44
|
+
def messages
|
45
|
+
return Messages.new(self)
|
46
|
+
end
|
47
|
+
|
48
|
+
def queues
|
49
|
+
return Queues.new(self)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
module IronMQ
|
4
|
+
class Messages
|
5
|
+
|
6
|
+
attr_accessor :client
|
7
|
+
|
8
|
+
def initialize(client)
|
9
|
+
@client = client
|
10
|
+
end
|
11
|
+
|
12
|
+
def path(options={})
|
13
|
+
path = "projects/#{@client.project_id}/queues/#{CGI::escape(options[:queue_name] || options['queue_name'] || @client.queue_name)}/messages"
|
14
|
+
end
|
15
|
+
|
16
|
+
# options:
|
17
|
+
# :queue_name => can specify an alternative queue name
|
18
|
+
# :timeout => amount of time before message goes back on the queue
|
19
|
+
def get(options={})
|
20
|
+
res = @client.parse_response(@client.get(path(options), options))
|
21
|
+
ret = []
|
22
|
+
res["messages"].each do |m|
|
23
|
+
ret << Message.new(self, m, options)
|
24
|
+
end
|
25
|
+
if options[:n] || options['n']
|
26
|
+
return ret
|
27
|
+
else
|
28
|
+
if ret.size > 0
|
29
|
+
return ret[0]
|
30
|
+
else
|
31
|
+
return nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# options:
|
37
|
+
# :queue_name => can specify an alternative queue name
|
38
|
+
# :delay => time to wait before message will be available on the queue
|
39
|
+
# :timeout => The time in seconds to wait after message is taken off the queue, before it is put back on. Delete before :timeout to ensure it does not go back on the queue.
|
40
|
+
# :expires_in => After this time, message will be automatically removed from the queue.
|
41
|
+
def post(payload, options={})
|
42
|
+
batch = false
|
43
|
+
if payload.is_a?(Array)
|
44
|
+
batch = true
|
45
|
+
msgs = payload
|
46
|
+
else
|
47
|
+
options[:body] = payload
|
48
|
+
msgs = []
|
49
|
+
msgs << options
|
50
|
+
end
|
51
|
+
to_send = {}
|
52
|
+
to_send[:messages] = msgs
|
53
|
+
res = @client.parse_response(@client.post(path(options), to_send))
|
54
|
+
if batch
|
55
|
+
return res
|
56
|
+
else
|
57
|
+
return ResponseBase.new({"id"=>res["ids"][0], "msg"=>res["msg"]})
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def delete(message_id, options={})
|
62
|
+
path2 = "#{self.path(options)}/#{message_id}"
|
63
|
+
res = @client.parse_response(@client.delete(path2))
|
64
|
+
return ResponseBase.new(res)
|
65
|
+
end
|
66
|
+
|
67
|
+
def release(message_id, options={})
|
68
|
+
path2 = "#{self.path(options)}/#{message_id}/release"
|
69
|
+
res = @client.parse_response(@client.post(path2, options))
|
70
|
+
return ResponseBase.new(res)
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
class ResponseBase
|
76
|
+
|
77
|
+
def initialize(res)
|
78
|
+
@data = res
|
79
|
+
end
|
80
|
+
|
81
|
+
def raw
|
82
|
+
@data
|
83
|
+
end
|
84
|
+
|
85
|
+
def [](key)
|
86
|
+
raw[key]
|
87
|
+
end
|
88
|
+
|
89
|
+
def id
|
90
|
+
raw["id"]
|
91
|
+
end
|
92
|
+
|
93
|
+
def msg
|
94
|
+
raw["msg"]
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
class Message < ResponseBase
|
100
|
+
|
101
|
+
def initialize(messages, res, options={})
|
102
|
+
super(res)
|
103
|
+
@messages = messages
|
104
|
+
@options = options
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
def body
|
109
|
+
raw["body"]
|
110
|
+
end
|
111
|
+
|
112
|
+
def delete
|
113
|
+
@messages.delete(self.id, @options)
|
114
|
+
end
|
115
|
+
|
116
|
+
def release(options={})
|
117
|
+
options2 = options || {}
|
118
|
+
options2 = options.merge(@options) if @options
|
119
|
+
@messages.release(self.id, options2)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
module IronMQ
|
4
|
+
class Queues
|
5
|
+
|
6
|
+
attr_accessor :client
|
7
|
+
|
8
|
+
def initialize(client)
|
9
|
+
@client = client
|
10
|
+
end
|
11
|
+
|
12
|
+
def path(options={})
|
13
|
+
path = "projects/#{@client.project_id}/queues"
|
14
|
+
if options[:name]
|
15
|
+
path << "/#{CGI::escape(options[:name])}"
|
16
|
+
end
|
17
|
+
path
|
18
|
+
end
|
19
|
+
|
20
|
+
def list(options={})
|
21
|
+
ret = []
|
22
|
+
r1 = @client.get("#{path(options)}", options)
|
23
|
+
#p r1
|
24
|
+
res = @client.parse_response(r1)
|
25
|
+
res.each do |q|
|
26
|
+
#p q
|
27
|
+
q = Queue.new(@client, q)
|
28
|
+
ret << q
|
29
|
+
end
|
30
|
+
ret
|
31
|
+
end
|
32
|
+
|
33
|
+
def clear(options={})
|
34
|
+
@client.logger.debug "Clearing queue #{options[:name]}"
|
35
|
+
r1 = @client.post("#{path(options)}/clear", options)
|
36
|
+
@client.logger.debug "Clear result: #{r1}"
|
37
|
+
r1
|
38
|
+
end
|
39
|
+
|
40
|
+
def delete(options={})
|
41
|
+
@client.logger.debug "Deleting queue #{options[:name]}"
|
42
|
+
r1 = @client.delete("#{path(options)}", options)
|
43
|
+
@client.logger.debug "Delete result: #{r1}"
|
44
|
+
r1
|
45
|
+
end
|
46
|
+
|
47
|
+
# options:
|
48
|
+
# :name => can specify an alternative queue name
|
49
|
+
def get(options={})
|
50
|
+
options[:name] ||= @client.queue_name
|
51
|
+
res = @client.parse_response(@client.get("#{path(options)}"))
|
52
|
+
return Queue.new(@client, res)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Update a queue
|
56
|
+
# options:
|
57
|
+
# :name => if not specified, will use global queue name
|
58
|
+
# :subscriptions => url's to subscribe to
|
59
|
+
def post(options={})
|
60
|
+
options[:name] ||= @client.queue_name
|
61
|
+
res = @client.parse_response(@client.post(path(options), options))
|
62
|
+
res
|
63
|
+
p res
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
class Queue
|
71
|
+
|
72
|
+
def initialize(client, res)
|
73
|
+
@client = client
|
74
|
+
@data = res
|
75
|
+
end
|
76
|
+
|
77
|
+
def raw
|
78
|
+
@data
|
79
|
+
end
|
80
|
+
|
81
|
+
def [](key)
|
82
|
+
raw[key]
|
83
|
+
end
|
84
|
+
|
85
|
+
def id
|
86
|
+
raw["id"]
|
87
|
+
end
|
88
|
+
|
89
|
+
def name
|
90
|
+
raw["name"]
|
91
|
+
end
|
92
|
+
|
93
|
+
def reload
|
94
|
+
load_queue
|
95
|
+
end
|
96
|
+
|
97
|
+
# Used if lazy loading
|
98
|
+
def load_queue
|
99
|
+
q = @client.queues.get(:name => name)
|
100
|
+
@client.logger.debug "GOT Q: " + q.inspect
|
101
|
+
@data = q.raw
|
102
|
+
q
|
103
|
+
end
|
104
|
+
|
105
|
+
def clear()
|
106
|
+
@client.queues.clear(:name => name)
|
107
|
+
end
|
108
|
+
|
109
|
+
def delete_queue()
|
110
|
+
@client.queues.delete(:name=>name)
|
111
|
+
end
|
112
|
+
|
113
|
+
def size
|
114
|
+
return raw["size"] if raw["size"]
|
115
|
+
return @size if @size
|
116
|
+
q = load_queue()
|
117
|
+
@size = q.size
|
118
|
+
@size
|
119
|
+
end
|
120
|
+
|
121
|
+
def total_messages
|
122
|
+
return raw["total_messages"] if raw["total_messages"]
|
123
|
+
return @total_messages if @total_messages
|
124
|
+
q = load_queue()
|
125
|
+
@total_messages = q.total_messages
|
126
|
+
@total_messages
|
127
|
+
end
|
128
|
+
|
129
|
+
def post(body, options={})
|
130
|
+
@client.messages.post(body, options.merge(:queue_name => name))
|
131
|
+
end
|
132
|
+
|
133
|
+
def get(options={})
|
134
|
+
@client.messages.get(options.merge(:queue_name => name))
|
135
|
+
end
|
136
|
+
|
137
|
+
# This will continuously poll for a message and pass it to the block. For example:
|
138
|
+
#
|
139
|
+
# queue.poll { |msg| puts msg.body }
|
140
|
+
#
|
141
|
+
# options:
|
142
|
+
# - :sleep_duration=>seconds => time between polls if msg is nil. default 1.
|
143
|
+
# - :break_if_nil=>true/false => if true, will break if msg is nil (ie: queue is empty)
|
144
|
+
def poll(options={}, &blk)
|
145
|
+
sleep_duration = options[:sleep_duration] || 1
|
146
|
+
while true
|
147
|
+
#p options
|
148
|
+
msg = get(options)
|
149
|
+
if msg.nil?
|
150
|
+
if options[:break_if_nil]
|
151
|
+
break
|
152
|
+
else
|
153
|
+
sleep sleep_duration
|
154
|
+
end
|
155
|
+
else
|
156
|
+
yield msg
|
157
|
+
msg.delete
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def delete(id, options={})
|
163
|
+
@client.messages.delete(id, options.merge(:queue_name => name))
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
|