tuber 0.0.1 → 0.5.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 +4 -4
- data/.github/workflows/ruby.yml +68 -0
- data/.gitignore +17 -0
- data/.yardopts +8 -0
- data/CHANGELOG.md +112 -0
- data/Gemfile +16 -0
- data/LICENSE.txt +27 -0
- data/README.md +379 -8
- data/Rakefile +35 -0
- data/TODO +1 -0
- data/examples/demo.rb +97 -0
- data/lib/tuber/configuration.rb +31 -0
- data/lib/tuber/connection.rb +366 -0
- data/lib/tuber/errors.rb +78 -0
- data/lib/tuber/job/collection.rb +160 -0
- data/lib/tuber/job/record.rb +226 -0
- data/lib/tuber/job.rb +4 -0
- data/lib/tuber/stats/fast_struct.rb +98 -0
- data/lib/tuber/stats/stat_struct.rb +52 -0
- data/lib/tuber/stats.rb +81 -0
- data/lib/tuber/tube/collection.rb +253 -0
- data/lib/tuber/tube/record.rb +231 -0
- data/lib/tuber/tube.rb +4 -0
- data/lib/tuber/version.rb +6 -0
- data/lib/tuber.rb +104 -2
- data/test/connection_test.rb +291 -0
- data/test/errors_test.rb +35 -0
- data/test/job_test.rb +250 -0
- data/test/jobs_test.rb +152 -0
- data/test/prompt_regexp_test.rb +59 -0
- data/test/stat_struct_test.rb +58 -0
- data/test/stats_test.rb +45 -0
- data/test/test_helper.rb +74 -0
- data/test/tube_test.rb +299 -0
- data/test/tuber_test.rb +112 -0
- data/test/tubes_test.rb +329 -0
- data/tuber.gemspec +33 -0
- metadata +112 -6
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Tuber
|
|
4
|
+
# Represents collection of tube related commands.
|
|
5
|
+
|
|
6
|
+
class Tubes
|
|
7
|
+
include Enumerable
|
|
8
|
+
|
|
9
|
+
# @!attribute client
|
|
10
|
+
# @return [Tuber] returns the client instance
|
|
11
|
+
attr_reader :client
|
|
12
|
+
|
|
13
|
+
# Creates new tubes instance.
|
|
14
|
+
#
|
|
15
|
+
# @param [Tuber] client The tuber client instance.
|
|
16
|
+
# @example
|
|
17
|
+
# Tuber::Tubes.new(@client)
|
|
18
|
+
#
|
|
19
|
+
def initialize(client)
|
|
20
|
+
@client = client
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def last_used
|
|
24
|
+
client.connection.tube_used
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def last_used=(tube_name)
|
|
28
|
+
client.connection.tube_used = tube_name
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Delegates transmit to the connection object.
|
|
32
|
+
#
|
|
33
|
+
# @see Tuber::Connection#transmit
|
|
34
|
+
def transmit(command, **options)
|
|
35
|
+
# Empty **options must not be forwarded: on Ruby 2.7 it arrives as an
|
|
36
|
+
# extra positional {} at the receiver.
|
|
37
|
+
return client.connection.transmit(command) if options.empty?
|
|
38
|
+
client.connection.transmit(command, **options)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Finds the specified beanstalk tube.
|
|
42
|
+
#
|
|
43
|
+
# @param [String] tube_name Name of the beanstalkd tube
|
|
44
|
+
# @return [Tuber::Tube] specified tube
|
|
45
|
+
# @example
|
|
46
|
+
# @pool.tubes.find('tube2')
|
|
47
|
+
# @pool.tubes['tube2']
|
|
48
|
+
# # => <Tuber::Tube name="tube2">
|
|
49
|
+
#
|
|
50
|
+
# @api public
|
|
51
|
+
def find(tube_name)
|
|
52
|
+
Tube.new(client, tube_name)
|
|
53
|
+
end
|
|
54
|
+
alias_method :[], :find
|
|
55
|
+
|
|
56
|
+
# Reserves a ready job looking at all watched tubes.
|
|
57
|
+
#
|
|
58
|
+
# @param [Integer] timeout Number of seconds before timing out.
|
|
59
|
+
# @param [Proc] block Callback to perform on the reserved job.
|
|
60
|
+
# @yield [job] Reserved tuber job.
|
|
61
|
+
# @return [Tuber::Job] Reserved tuber job.
|
|
62
|
+
# @example
|
|
63
|
+
# @client.tubes.reserve { |job| process(job) }
|
|
64
|
+
# # => <Tuber::Job id=5 body="foo">
|
|
65
|
+
#
|
|
66
|
+
# @api public
|
|
67
|
+
def reserve(timeout=nil, &block)
|
|
68
|
+
res = transmit(
|
|
69
|
+
timeout ? "reserve-with-timeout #{timeout}" : 'reserve')
|
|
70
|
+
job = Job.new(client, res)
|
|
71
|
+
block.call(job) if block_given?
|
|
72
|
+
job
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Reserves a batch of ready jobs from watched tubes.
|
|
76
|
+
#
|
|
77
|
+
# Without a +timeout+ the call is non-blocking and may return an empty array.
|
|
78
|
+
# With a positive +timeout+ it long-polls, blocking up to +timeout+ seconds
|
|
79
|
+
# for the first job before draining whatever is ready, up to +count+.
|
|
80
|
+
#
|
|
81
|
+
# @param [Integer] count Maximum number of jobs to reserve
|
|
82
|
+
# @param [Integer] timeout Seconds to long-poll for the first job (nil = non-blocking)
|
|
83
|
+
# @return [Array<Tuber::Job>] Array of reserved jobs (empty if none available)
|
|
84
|
+
# @raise [Tuber::DeadlineSoonError] A reserved job's TTR is about to expire
|
|
85
|
+
# @example
|
|
86
|
+
# @client.tubes.reserve_batch(10) # non-blocking
|
|
87
|
+
# @client.tubes.reserve_batch(10, 30) # long-poll up to 30s
|
|
88
|
+
# # => [<Tuber::Job id=1 body="foo">, ...]
|
|
89
|
+
#
|
|
90
|
+
# @api public
|
|
91
|
+
def reserve_batch(count, timeout = nil)
|
|
92
|
+
results = client.connection.reserve_batch(count, timeout)
|
|
93
|
+
results.map { |res| Job.new(client, res) }
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Sets the reserve mode for the connection.
|
|
97
|
+
#
|
|
98
|
+
# @param [String, Symbol] mode The reserve mode ('weighted' or 'fifo')
|
|
99
|
+
# @return [Hash] Response from beanstalkd
|
|
100
|
+
# @example
|
|
101
|
+
# @client.tubes.reserve_mode(:weighted)
|
|
102
|
+
# @client.tubes.reserve_mode(:fifo)
|
|
103
|
+
#
|
|
104
|
+
# @api public
|
|
105
|
+
def reserve_mode(mode)
|
|
106
|
+
transmit("reserve-mode #{mode}")
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Reserves a specific job by its ID.
|
|
110
|
+
#
|
|
111
|
+
# @param [Integer, String] id The job ID to reserve
|
|
112
|
+
# @return [Tuber::Job, nil] The reserved job, or nil if not found
|
|
113
|
+
# @example
|
|
114
|
+
# @client.tubes.reserve_job(123)
|
|
115
|
+
# # => <Tuber::Job id=123 body="foo">
|
|
116
|
+
#
|
|
117
|
+
# @api public
|
|
118
|
+
def reserve_job(id)
|
|
119
|
+
res = transmit("reserve-job #{id}")
|
|
120
|
+
Job.new(client, res)
|
|
121
|
+
rescue Tuber::NotFoundError
|
|
122
|
+
nil
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Returns stats for a job group.
|
|
126
|
+
#
|
|
127
|
+
# @param [String] group The group name
|
|
128
|
+
# @return [Tuber::StatStruct] Struct of group stats
|
|
129
|
+
# @example
|
|
130
|
+
# @client.tubes.stats_group('batch-1')
|
|
131
|
+
# # => #<StatStruct name="batch-1" ready=5 reserved=0 delayed=0 buried=0 waiting_jobs=0>
|
|
132
|
+
#
|
|
133
|
+
# @api public
|
|
134
|
+
def stats_group(group)
|
|
135
|
+
res = transmit("stats-group #{group}")
|
|
136
|
+
StatStruct.from_hash(res[:body])
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# List of all known beanstalk tubes.
|
|
140
|
+
#
|
|
141
|
+
# @return [Array<Tuber::Tube>] List of all beanstalk tubes.
|
|
142
|
+
# @example
|
|
143
|
+
# @client.tubes.all
|
|
144
|
+
# # => [<Tuber::Tube name="tube2">, <Tuber::Tube name="tube3">]
|
|
145
|
+
#
|
|
146
|
+
# @api public
|
|
147
|
+
def all
|
|
148
|
+
transmit('list-tubes')[:body].map do |tube_name|
|
|
149
|
+
Tube.new(client, tube_name)
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Calls the given block once for each known beanstalk tube, passing that element as a parameter.
|
|
154
|
+
#
|
|
155
|
+
# @return An Enumerator is returned if no block is given.
|
|
156
|
+
# @example
|
|
157
|
+
# @pool.tubes.each {|t| puts t.name}
|
|
158
|
+
#
|
|
159
|
+
# @api public
|
|
160
|
+
def each(&block)
|
|
161
|
+
all.each(&block)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# List of watched beanstalk tubes.
|
|
165
|
+
#
|
|
166
|
+
# @return [Array<Tuber::Tube>] List of watched beanstalk tubes.
|
|
167
|
+
# @example
|
|
168
|
+
# @client.tubes.watched
|
|
169
|
+
# # => [<Tuber::Tube name="tube2">, <Tuber::Tube name="tube3">]
|
|
170
|
+
#
|
|
171
|
+
# @api public
|
|
172
|
+
def watched
|
|
173
|
+
last_watched = transmit('list-tubes-watched')[:body]
|
|
174
|
+
client.connection.tubes_watched = last_watched.dup
|
|
175
|
+
last_watched.map do |tube_name|
|
|
176
|
+
Tube.new(client, tube_name)
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Currently used beanstalk tube.
|
|
181
|
+
#
|
|
182
|
+
# @return [Tuber::Tube] Currently used beanstalk tube.
|
|
183
|
+
# @example
|
|
184
|
+
# @client.tubes.used
|
|
185
|
+
# # => <Tuber::Tube name="tube2">
|
|
186
|
+
#
|
|
187
|
+
# @api public
|
|
188
|
+
def used
|
|
189
|
+
last_used = transmit('list-tube-used')[:id]
|
|
190
|
+
Tube.new(client, last_used)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Add specified beanstalkd tubes as watched.
|
|
194
|
+
#
|
|
195
|
+
# @param [*String] names Name of tubes to watch
|
|
196
|
+
# @raise [Tuber::InvalidTubeName] Tube to watch was invalid.
|
|
197
|
+
# @example
|
|
198
|
+
# @client.tubes.watch('foo', 'bar')
|
|
199
|
+
#
|
|
200
|
+
# @api public
|
|
201
|
+
def watch(*names, weight: nil)
|
|
202
|
+
names.each do |t|
|
|
203
|
+
cmd = weight ? "watch #{t} #{weight}" : "watch #{t}"
|
|
204
|
+
transmit cmd
|
|
205
|
+
client.connection.add_to_watched(t)
|
|
206
|
+
end
|
|
207
|
+
rescue BadFormatError => ex
|
|
208
|
+
raise InvalidTubeName, "Tube in '#{ex.cmd}' is invalid!"
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Add specified beanstalkd tubes as watched and ignores all other tubes.
|
|
212
|
+
#
|
|
213
|
+
# @param [*String] names Name of tubes to watch
|
|
214
|
+
# @raise [Tuber::InvalidTubeName] Tube to watch was invalid.
|
|
215
|
+
# @example
|
|
216
|
+
# @client.tubes.watch!('foo', 'bar')
|
|
217
|
+
#
|
|
218
|
+
# @api public
|
|
219
|
+
def watch!(*names)
|
|
220
|
+
old_tubes = watched.map(&:name) - names.map(&:to_s)
|
|
221
|
+
watch(*names)
|
|
222
|
+
ignore(*old_tubes)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Ignores specified beanstalkd tubes.
|
|
226
|
+
#
|
|
227
|
+
# @param [*String] names Name of tubes to ignore
|
|
228
|
+
# @example
|
|
229
|
+
# @client.tubes.ignore('foo', 'bar')
|
|
230
|
+
#
|
|
231
|
+
# @api public
|
|
232
|
+
def ignore(*names)
|
|
233
|
+
names.each do |w|
|
|
234
|
+
transmit "ignore #{w}"
|
|
235
|
+
client.connection.remove_from_watched(w)
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Set specified tube as used.
|
|
240
|
+
#
|
|
241
|
+
# @param [String] tube Tube to be used.
|
|
242
|
+
# @example
|
|
243
|
+
# @conn.tubes.use("some-tube")
|
|
244
|
+
#
|
|
245
|
+
def use(tube)
|
|
246
|
+
return tube if last_used == tube
|
|
247
|
+
transmit("use #{tube}")
|
|
248
|
+
self.last_used = tube
|
|
249
|
+
rescue BadFormatError
|
|
250
|
+
raise InvalidTubeName, "Tube cannot be named '#{tube}'"
|
|
251
|
+
end
|
|
252
|
+
end # Tubes
|
|
253
|
+
end # Tuber
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Tuber
|
|
4
|
+
# Beanstalk tube which contains jobs which can be inserted, reserved, et al.
|
|
5
|
+
class Tube
|
|
6
|
+
|
|
7
|
+
# @!attribute name
|
|
8
|
+
# @return [String] name of the tube
|
|
9
|
+
# @!attribute client
|
|
10
|
+
# @return [Tuber] returns the client instance
|
|
11
|
+
attr_reader :name, :client
|
|
12
|
+
|
|
13
|
+
# Fetches the specified tube.
|
|
14
|
+
#
|
|
15
|
+
# @param [Tuber] client The tuber client instance.
|
|
16
|
+
# @param [String] name The name for this tube.
|
|
17
|
+
# @example
|
|
18
|
+
# Tuber::Tube.new(@client, 'tube-name')
|
|
19
|
+
#
|
|
20
|
+
def initialize(client, name)
|
|
21
|
+
@client = client
|
|
22
|
+
@name = name.to_s
|
|
23
|
+
@mutex = Mutex.new
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Delegates transmit to the connection object.
|
|
27
|
+
#
|
|
28
|
+
# @see Tuber::Connection#transmit
|
|
29
|
+
def transmit(command, options={})
|
|
30
|
+
# Empty **options must not be forwarded: on Ruby 2.7 it arrives as an
|
|
31
|
+
# extra positional {} at the receiver.
|
|
32
|
+
return client.connection.transmit(command) if options.empty?
|
|
33
|
+
client.connection.transmit(command, **options)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Inserts job with specified body onto tube.
|
|
37
|
+
#
|
|
38
|
+
# @param [String] body The data to store with this job.
|
|
39
|
+
# @param [Hash{String => Integer}] options The settings associated with this job.
|
|
40
|
+
# @option options [Integer] pri priority for this job
|
|
41
|
+
# @option options [Integer] ttr time to respond for this job
|
|
42
|
+
# @option options [Integer] delay delay for this job
|
|
43
|
+
# @option options [String, Array] idp idempotency key, or [key, ttl] pair
|
|
44
|
+
# @option options [String, Array] con concurrency key, or [key, limit] pair
|
|
45
|
+
# @option options [String] grp group key for this job
|
|
46
|
+
# @option options [String] aft after-group key (run after group completes)
|
|
47
|
+
# @return [Hash{String => String, Number}] beanstalkd command response
|
|
48
|
+
# @example
|
|
49
|
+
# @tube.put "data", pri: 1000, ttr: 10, delay: 5
|
|
50
|
+
# @tube.put "data", idp: "report", con: ["db", 3], grp: "batch-1", aft: "batch-0"
|
|
51
|
+
#
|
|
52
|
+
# @api public
|
|
53
|
+
def put(body, options={})
|
|
54
|
+
safe_use do
|
|
55
|
+
serialized_body = config.job_serializer.call(body)
|
|
56
|
+
|
|
57
|
+
options = {
|
|
58
|
+
:pri => config.default_put_pri,
|
|
59
|
+
:delay => config.default_put_delay,
|
|
60
|
+
:ttr => config.default_put_ttr
|
|
61
|
+
}.merge(options)
|
|
62
|
+
|
|
63
|
+
cmd_options = "#{options[:pri]} #{options[:delay]} #{options[:ttr]} #{serialized_body.bytesize}"
|
|
64
|
+
|
|
65
|
+
tags = []
|
|
66
|
+
if options[:idp]
|
|
67
|
+
tags << (options[:idp].is_a?(Array) ? "idp:#{options[:idp].join(':')}" : "idp:#{options[:idp]}")
|
|
68
|
+
end
|
|
69
|
+
if options[:con]
|
|
70
|
+
tags << (options[:con].is_a?(Array) ? "con:#{options[:con].join(':')}" : "con:#{options[:con]}")
|
|
71
|
+
end
|
|
72
|
+
tags << "grp:#{options[:grp]}" if options[:grp]
|
|
73
|
+
tags << "aft:#{options[:aft]}" if options[:aft]
|
|
74
|
+
|
|
75
|
+
cmd_options = "#{cmd_options} #{tags.join(' ')}" if tags.any?
|
|
76
|
+
transmit("put #{cmd_options}\r\n#{serialized_body}")
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Peek at next job within this tube in given `state`.
|
|
81
|
+
#
|
|
82
|
+
# @param [String] state The job state to peek at (`ready`, `buried`, `delayed`)
|
|
83
|
+
# @return [Tuber::Job] The next job within this tube.
|
|
84
|
+
# @example
|
|
85
|
+
# @tube.peek(:ready) # => <Tuber::Job id=5 body=foo>
|
|
86
|
+
#
|
|
87
|
+
# @api public
|
|
88
|
+
def peek(state)
|
|
89
|
+
safe_use do
|
|
90
|
+
res = transmit("peek-#{state}")
|
|
91
|
+
Job.new(client, res)
|
|
92
|
+
end
|
|
93
|
+
rescue Tuber::NotFoundError
|
|
94
|
+
# Return nil if not found
|
|
95
|
+
nil
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Reserves the next job from tube.
|
|
99
|
+
#
|
|
100
|
+
# @param [Integer] timeout Number of seconds before timing out
|
|
101
|
+
# @param [Proc] block Callback to perform on reserved job
|
|
102
|
+
# @yield [job] Job that was reserved.
|
|
103
|
+
# @return [Tuber::Job] Job that was reserved.
|
|
104
|
+
# @example
|
|
105
|
+
# @tube.reserve # => <Tuber::Job id=5 body=foo>
|
|
106
|
+
#
|
|
107
|
+
# @api public
|
|
108
|
+
def reserve(timeout=nil, &block)
|
|
109
|
+
client.tubes.watch!(self.name)
|
|
110
|
+
client.tubes.reserve(timeout, &block)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Kick specified number of jobs from buried to ready state.
|
|
114
|
+
#
|
|
115
|
+
# @param [Integer] bounds The number of jobs to kick.
|
|
116
|
+
# @return [Hash{String => String, Number}] Beanstalkd command response
|
|
117
|
+
# @example
|
|
118
|
+
# @tube.kick(5)
|
|
119
|
+
#
|
|
120
|
+
# @api public
|
|
121
|
+
def kick(bounds=1)
|
|
122
|
+
safe_use { transmit("kick #{bounds}") }
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Returns related stats for this tube.
|
|
126
|
+
#
|
|
127
|
+
# @return [Tuber::StatStruct] Struct of tube related values
|
|
128
|
+
# @example
|
|
129
|
+
# @tube.stats.current_jobs_delayed # => 24
|
|
130
|
+
#
|
|
131
|
+
# @api public
|
|
132
|
+
def stats
|
|
133
|
+
res = transmit("stats-tube #{name}")
|
|
134
|
+
StatStruct.from_hash(res[:body])
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Pause the execution of this tube for specified `delay`.
|
|
138
|
+
#
|
|
139
|
+
# @param [Integer] delay Number of seconds to delay tube execution
|
|
140
|
+
# @return [Array<Hash{String => String, Number}>] Beanstalkd command response
|
|
141
|
+
# @example
|
|
142
|
+
# @tube.pause(10)
|
|
143
|
+
#
|
|
144
|
+
# @api public
|
|
145
|
+
def pause(delay)
|
|
146
|
+
transmit("pause-tube #{name} #{delay}")
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Atomically deletes all jobs from the tube.
|
|
150
|
+
#
|
|
151
|
+
# @return [Integer] Number of jobs flushed
|
|
152
|
+
# @example
|
|
153
|
+
# @tube.flush # => 5
|
|
154
|
+
#
|
|
155
|
+
# @api public
|
|
156
|
+
def flush
|
|
157
|
+
res = transmit("flush-tube #{name}")
|
|
158
|
+
res[:id].to_i
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Atomically deletes all buried jobs from the tube. Ready, delayed, and
|
|
162
|
+
# reserved jobs are left untouched. (Tuber only.)
|
|
163
|
+
#
|
|
164
|
+
# @return [Integer] Number of buried jobs flushed
|
|
165
|
+
# @example
|
|
166
|
+
# @tube.flush_buried # => 3
|
|
167
|
+
#
|
|
168
|
+
# @api public
|
|
169
|
+
def flush_buried
|
|
170
|
+
res = transmit("flush-buried #{name}")
|
|
171
|
+
res[:id].to_i
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Clears all unreserved jobs in all states from the tube
|
|
175
|
+
#
|
|
176
|
+
# @example
|
|
177
|
+
# @tube.clear
|
|
178
|
+
#
|
|
179
|
+
def clear
|
|
180
|
+
client.tubes.watch!(self.name)
|
|
181
|
+
%w(delayed buried ready).each do |state|
|
|
182
|
+
while job = self.peek(state.to_sym)
|
|
183
|
+
begin
|
|
184
|
+
job.delete
|
|
185
|
+
rescue Tuber::UnexpectedResponse, Tuber::NotFoundError
|
|
186
|
+
# swallow any issues
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
client.tubes.ignore(name)
|
|
191
|
+
rescue Tuber::NotIgnoredError
|
|
192
|
+
# swallow any issues
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# String representation of tube.
|
|
196
|
+
#
|
|
197
|
+
# @return [String] Representation of tube including name.
|
|
198
|
+
# @example
|
|
199
|
+
# @tube.to_s # => "#<Tuber::Tube name=foo>"
|
|
200
|
+
#
|
|
201
|
+
def to_s
|
|
202
|
+
"#<Tuber::Tube name=#{name.inspect}>"
|
|
203
|
+
end
|
|
204
|
+
alias :inspect :to_s
|
|
205
|
+
|
|
206
|
+
protected
|
|
207
|
+
|
|
208
|
+
# Transmits a beanstalk command that requires this tube to be set as used.
|
|
209
|
+
#
|
|
210
|
+
# @param [Proc] block Beanstalk command to transmit.
|
|
211
|
+
# @return [Object] Result of block passed
|
|
212
|
+
# @example
|
|
213
|
+
# safe_use { transmit("kick 1") }
|
|
214
|
+
# # => "Response to kick command"
|
|
215
|
+
#
|
|
216
|
+
def safe_use(&block)
|
|
217
|
+
@mutex.lock
|
|
218
|
+
client.tubes.use(self.name)
|
|
219
|
+
yield
|
|
220
|
+
ensure
|
|
221
|
+
@mutex.unlock
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# Returns configuration options for tuber
|
|
225
|
+
#
|
|
226
|
+
# @return [Tuber::Configuration] configuration object
|
|
227
|
+
def config
|
|
228
|
+
Tuber.configuration
|
|
229
|
+
end
|
|
230
|
+
end # Tube
|
|
231
|
+
end # Tuber
|
data/lib/tuber/tube.rb
ADDED
data/lib/tuber.rb
CHANGED
|
@@ -1,5 +1,107 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
require 'thread' unless defined?(Mutex)
|
|
4
|
+
|
|
5
|
+
%w(version configuration errors connection tube job stats).each do |f|
|
|
6
|
+
require "tuber/#{f}"
|
|
5
7
|
end
|
|
8
|
+
|
|
9
|
+
class Tuber
|
|
10
|
+
|
|
11
|
+
# @!attribute connection
|
|
12
|
+
# @return <Tuber::Connection> returns the associated connection object
|
|
13
|
+
attr_reader :connection
|
|
14
|
+
|
|
15
|
+
# Initialize new instance of Tuber
|
|
16
|
+
#
|
|
17
|
+
# @param [String] address in the form "host:port"
|
|
18
|
+
# @example
|
|
19
|
+
# Tuber.new('127.0.0.1:11300')
|
|
20
|
+
#
|
|
21
|
+
# ENV['TUBER_URL'] = '127.0.0.1:11300'
|
|
22
|
+
# @b = Tuber.new
|
|
23
|
+
# @b.connection.host # => '127.0.0.1'
|
|
24
|
+
# @b.connection.port # => '11300'
|
|
25
|
+
#
|
|
26
|
+
def initialize(address=nil)
|
|
27
|
+
@connection = Connection.new(address)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Returns Tuber::Tubes object for accessing tube related functions.
|
|
31
|
+
#
|
|
32
|
+
# @return [Tuber::Tubes] tubes object
|
|
33
|
+
# @api public
|
|
34
|
+
def tubes
|
|
35
|
+
@tubes ||= Tuber::Tubes.new(self)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Returns Tuber::Jobs object for accessing job related functions.
|
|
39
|
+
#
|
|
40
|
+
# @return [Tuber::Jobs] jobs object
|
|
41
|
+
# @api public
|
|
42
|
+
def jobs
|
|
43
|
+
@jobs ||= Tuber::Jobs.new(self)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Returns Tuber::Stats object for accessing beanstalk stats.
|
|
47
|
+
#
|
|
48
|
+
# @return [Tuber::Stats] stats object
|
|
49
|
+
# @api public
|
|
50
|
+
def stats
|
|
51
|
+
@stats ||= Stats.new(self)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Puts the server into drain mode, rejecting new puts.
|
|
55
|
+
#
|
|
56
|
+
# @return [Hash] Response from beanstalkd
|
|
57
|
+
# @example
|
|
58
|
+
# @tuber_instance.drain
|
|
59
|
+
#
|
|
60
|
+
def drain
|
|
61
|
+
connection.transmit("drain")
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Takes the server out of drain mode, allowing new puts.
|
|
65
|
+
#
|
|
66
|
+
# @return [Hash] Response from beanstalkd
|
|
67
|
+
# @example
|
|
68
|
+
# @tuber_instance.undrain
|
|
69
|
+
#
|
|
70
|
+
def undrain
|
|
71
|
+
connection.transmit("undrain")
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Closes the related connection
|
|
75
|
+
#
|
|
76
|
+
# @example
|
|
77
|
+
# @tuber_instance.close
|
|
78
|
+
#
|
|
79
|
+
def close
|
|
80
|
+
connection.close if connection
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
protected
|
|
84
|
+
|
|
85
|
+
class << self
|
|
86
|
+
# Yields a configuration block
|
|
87
|
+
#
|
|
88
|
+
# @example
|
|
89
|
+
# Tuber.configure do |config|
|
|
90
|
+
# config.job_parser = lamda { |body| Yaml.load(body)}
|
|
91
|
+
# end
|
|
92
|
+
#
|
|
93
|
+
def configure(&block)
|
|
94
|
+
yield(configuration) if block_given?
|
|
95
|
+
configuration
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Returns the configuration options set for Backburner
|
|
99
|
+
#
|
|
100
|
+
# @example
|
|
101
|
+
# Tuber.configuration.default_put_ttr => 120
|
|
102
|
+
#
|
|
103
|
+
def configuration
|
|
104
|
+
@_configuration ||= Configuration.new
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end # Tuber
|