faktory_worker_ruby 1.1.1 → 1.2.0
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/ci.yml +3 -3
- data/.standard.yml +12 -0
- data/Changes.md +6 -0
- data/Gemfile +5 -2
- data/Gemfile.lock +46 -20
- data/Rakefile +5 -4
- data/faktory_worker_ruby.gemspec +17 -19
- data/lib/active_job/queue_adapters/faktory_adapter.rb +10 -10
- data/lib/faktory/batch.rb +7 -7
- data/lib/faktory/cli.rb +51 -55
- data/lib/faktory/client.rb +46 -36
- data/lib/faktory/connection.rb +4 -3
- data/lib/faktory/exception_handler.rb +10 -13
- data/lib/faktory/fetch.rb +3 -4
- data/lib/faktory/io.rb +3 -2
- data/lib/faktory/job.rb +14 -15
- data/lib/faktory/job_logger.rb +0 -1
- data/lib/faktory/launcher.rb +12 -14
- data/lib/faktory/logging.rb +9 -9
- data/lib/faktory/manager.rb +8 -11
- data/lib/faktory/middleware/batch.rb +1 -0
- data/lib/faktory/middleware/chain.rb +3 -2
- data/lib/faktory/middleware/i18n.rb +2 -1
- data/lib/faktory/mutate.rb +10 -11
- data/lib/faktory/processor.rb +27 -31
- data/lib/faktory/rails.rb +49 -46
- data/lib/faktory/testing.rb +24 -26
- data/lib/faktory/tracking.rb +3 -4
- data/lib/faktory/util.rb +11 -12
- data/lib/faktory/version.rb +2 -1
- data/lib/faktory.rb +25 -21
- data/lib/faktory_worker_ruby.rb +1 -1
- metadata +4 -3
data/lib/faktory/client.rb
CHANGED
@@ -1,14 +1,17 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
1
|
+
require "socket"
|
2
|
+
require "json"
|
3
|
+
require "uri"
|
4
|
+
require "cgi"
|
5
|
+
require "digest"
|
6
|
+
require "securerandom"
|
7
|
+
require "timeout"
|
8
|
+
require "faktory/io"
|
8
9
|
|
9
10
|
module Faktory
|
10
11
|
class BaseError < StandardError; end
|
12
|
+
|
11
13
|
class CommandError < BaseError; end
|
14
|
+
|
12
15
|
class ParseError < BaseError; end
|
13
16
|
|
14
17
|
# Faktory::Client provides a low-level connection to a Faktory server
|
@@ -33,7 +36,6 @@ module Faktory
|
|
33
36
|
Digest.hexencode(hashing)
|
34
37
|
end
|
35
38
|
|
36
|
-
|
37
39
|
# Called when booting the worker process to signal that this process
|
38
40
|
# will consume jobs and send BEAT.
|
39
41
|
def self.worker!
|
@@ -49,13 +51,13 @@ module Faktory
|
|
49
51
|
# MY_FAKTORY_URL=tcp://:somepass@my-server.example.com:7419
|
50
52
|
#
|
51
53
|
# Note above, the URL can contain the password for secure installations.
|
52
|
-
def initialize(url: uri_from_env ||
|
54
|
+
def initialize(url: uri_from_env || "tcp://localhost:7419", debug: false, timeout: DEFAULT_TIMEOUT)
|
53
55
|
super
|
54
56
|
@debug = debug
|
55
57
|
@location = URI(url)
|
56
58
|
@timeout = timeout
|
57
59
|
|
58
|
-
|
60
|
+
open_socket(@timeout)
|
59
61
|
end
|
60
62
|
|
61
63
|
def close
|
@@ -162,6 +164,11 @@ module Faktory
|
|
162
164
|
# Returned value will either be the JID String if successful OR
|
163
165
|
# a symbol corresponding to an error.
|
164
166
|
def push(job)
|
167
|
+
job["jid"] ||= SecureRandom.hex(12)
|
168
|
+
job["queue"] ||= "default"
|
169
|
+
raise ArgumentError, "Missing `jobtype` attribute: #{job.inspect}" unless job["jobtype"]
|
170
|
+
raise ArgumentError, "Missing `args` attribute: #{job.inspect}" unless job["args"]
|
171
|
+
|
165
172
|
transaction do
|
166
173
|
command "PUSH", Faktory.dump_json(job)
|
167
174
|
ok(job["jid"])
|
@@ -180,14 +187,14 @@ module Faktory
|
|
180
187
|
|
181
188
|
def ack(jid)
|
182
189
|
transaction do
|
183
|
-
command("ACK", %
|
190
|
+
command("ACK", %({"jid":"#{jid}"}))
|
184
191
|
ok
|
185
192
|
end
|
186
193
|
end
|
187
194
|
|
188
195
|
def fail(jid, ex)
|
189
196
|
transaction do
|
190
|
-
command("FAIL", Faktory.dump_json({
|
197
|
+
command("FAIL", Faktory.dump_json({message: ex.message[0...1000],
|
191
198
|
errtype: ex.class.name,
|
192
199
|
jid: jid,
|
193
200
|
backtrace: ex.backtrace}))
|
@@ -204,7 +211,7 @@ module Faktory
|
|
204
211
|
# Return a string signal to process, legal values are "quiet" or "terminate".
|
205
212
|
# The quiet signal is informative: the server won't allow this process to FETCH
|
206
213
|
# any more jobs anyways.
|
207
|
-
def beat(current_state = nil, hash)
|
214
|
+
def beat(current_state = nil, hash = {})
|
208
215
|
transaction do
|
209
216
|
hash["wid"] = @@random_process_wid
|
210
217
|
hash["current_state"] = current_state if current_state
|
@@ -239,9 +246,9 @@ module Faktory
|
|
239
246
|
@location.scheme =~ /tls/
|
240
247
|
end
|
241
248
|
|
242
|
-
def
|
249
|
+
def open_socket(timeout = DEFAULT_TIMEOUT)
|
243
250
|
if tls?
|
244
|
-
require
|
251
|
+
require "openssl"
|
245
252
|
sock = TCPSocket.new(@location.hostname, @location.port)
|
246
253
|
sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true)
|
247
254
|
|
@@ -259,12 +266,12 @@ module Faktory
|
|
259
266
|
end
|
260
267
|
|
261
268
|
payload = {
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
269
|
+
wid: @@random_process_wid,
|
270
|
+
hostname: Socket.gethostname,
|
271
|
+
pid: $$,
|
272
|
+
labels: Faktory.options[:labels] || ["ruby-#{RUBY_VERSION}"],
|
273
|
+
username: @location.user,
|
274
|
+
v: 2
|
268
275
|
}
|
269
276
|
|
270
277
|
hi = result
|
@@ -286,7 +293,7 @@ module Faktory
|
|
286
293
|
iter = (hash["i"] || 1).to_i
|
287
294
|
raise ArgumentError, "Invalid hashing" if iter < 1
|
288
295
|
|
289
|
-
payload["pwdhash"] = HASHER.(iter, pwd, salt)
|
296
|
+
payload["pwdhash"] = HASHER.call(iter, CGI.unescape(pwd), salt)
|
290
297
|
end
|
291
298
|
end
|
292
299
|
|
@@ -307,7 +314,7 @@ module Faktory
|
|
307
314
|
# have an underlying socket. Now if you disable testing and try to use that
|
308
315
|
# client, it will crash without a socket. This open() handles that case to
|
309
316
|
# transparently open a socket.
|
310
|
-
|
317
|
+
open_socket(@timeout) if !@sock
|
311
318
|
|
312
319
|
begin
|
313
320
|
yield
|
@@ -315,9 +322,13 @@ module Faktory
|
|
315
322
|
if retryable
|
316
323
|
retryable = false
|
317
324
|
|
318
|
-
|
325
|
+
begin
|
326
|
+
@sock.close
|
327
|
+
rescue
|
328
|
+
nil
|
329
|
+
end
|
319
330
|
@sock = nil
|
320
|
-
|
331
|
+
open_socket(@timeout)
|
321
332
|
retry
|
322
333
|
else
|
323
334
|
raise
|
@@ -332,15 +343,15 @@ module Faktory
|
|
332
343
|
debug "< #{line}" if @debug
|
333
344
|
raise Errno::ECONNRESET, "No response" unless line
|
334
345
|
chr = line[0]
|
335
|
-
if chr ==
|
346
|
+
if chr == "+"
|
336
347
|
line[1..-1].strip
|
337
|
-
elsif chr ==
|
348
|
+
elsif chr == "$"
|
338
349
|
count = line[1..-1].strip.to_i
|
339
350
|
return nil if count == -1
|
340
351
|
data = read(count) if count > 0
|
341
|
-
|
352
|
+
_ = gets # read extra linefeeds
|
342
353
|
data
|
343
|
-
elsif chr ==
|
354
|
+
elsif chr == "-"
|
344
355
|
# Server can respond with:
|
345
356
|
#
|
346
357
|
# -ERR Something unexpected
|
@@ -358,15 +369,15 @@ module Faktory
|
|
358
369
|
end
|
359
370
|
end
|
360
371
|
|
361
|
-
def ok(retval=true)
|
372
|
+
def ok(retval = true)
|
362
373
|
resp = result
|
363
374
|
return retval if resp == "OK"
|
364
|
-
|
375
|
+
resp[0].to_sym
|
365
376
|
end
|
366
377
|
|
367
378
|
def result!
|
368
379
|
resp = result
|
369
|
-
return nil if resp
|
380
|
+
return nil if resp.nil?
|
370
381
|
raise CommandError, resp[0] if !resp.is_a?(String)
|
371
382
|
resp
|
372
383
|
end
|
@@ -374,21 +385,20 @@ module Faktory
|
|
374
385
|
# FAKTORY_PROVIDER=MY_FAKTORY_URL
|
375
386
|
# MY_FAKTORY_URL=tcp://:some-pass@some-hostname:7419
|
376
387
|
def uri_from_env
|
377
|
-
prov = ENV[
|
388
|
+
prov = ENV["FAKTORY_PROVIDER"]
|
378
389
|
if prov
|
379
390
|
raise(ArgumentError, <<-EOM) if prov.index(":")
|
380
391
|
Invalid FAKTORY_PROVIDER '#{prov}', it should be the name of the ENV variable that contains the URL
|
381
392
|
FAKTORY_PROVIDER=MY_FAKTORY_URL
|
382
393
|
MY_FAKTORY_URL=tcp://:some-pass@some-hostname:7419
|
383
|
-
|
394
|
+
EOM
|
384
395
|
val = ENV[prov]
|
385
396
|
return URI(val) if val
|
386
397
|
end
|
387
398
|
|
388
|
-
val = ENV[
|
399
|
+
val = ENV["FAKTORY_URL"]
|
389
400
|
return URI(val) if val
|
390
401
|
nil
|
391
402
|
end
|
392
|
-
|
393
403
|
end
|
394
404
|
end
|
data/lib/faktory/connection.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
|
+
require "connection_pool"
|
3
4
|
|
4
5
|
module Faktory
|
5
6
|
class Connection
|
6
7
|
class << self
|
7
|
-
def create(options={})
|
8
|
+
def create(options = {})
|
8
9
|
size = Faktory.worker? ? (Faktory.options[:concurrency] + 2) : 5
|
9
|
-
ConnectionPool.new(:
|
10
|
+
ConnectionPool.new(timeout: options[:pool_timeout] || 1, size: size) do
|
10
11
|
Faktory::Client.new(**options)
|
11
12
|
end
|
12
13
|
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
|
+
require "faktory"
|
3
4
|
|
4
5
|
module Faktory
|
5
6
|
module ExceptionHandler
|
6
|
-
|
7
7
|
class Logger
|
8
|
-
def call(ex,
|
9
|
-
Faktory.logger.warn(Faktory.dump_json(
|
8
|
+
def call(ex, ctx_hash)
|
9
|
+
Faktory.logger.warn(Faktory.dump_json(ctx_hash)) if !ctx_hash.empty?
|
10
10
|
Faktory.logger.warn "#{ex.class.name}: #{ex.message}"
|
11
11
|
Faktory.logger.warn ex.backtrace.join("\n") unless ex.backtrace.nil?
|
12
12
|
end
|
@@ -15,17 +15,14 @@ module Faktory
|
|
15
15
|
Faktory.error_handlers << Faktory::ExceptionHandler::Logger.new
|
16
16
|
end
|
17
17
|
|
18
|
-
def handle_exception(ex,
|
18
|
+
def handle_exception(ex, ctx_hash = {})
|
19
19
|
Faktory.error_handlers.each do |handler|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
Faktory.logger.error ex.backtrace.join("\n") unless ex.backtrace.nil?
|
26
|
-
end
|
20
|
+
handler.call(ex, ctx_hash)
|
21
|
+
rescue => ex
|
22
|
+
Faktory.logger.error "!!! ERROR HANDLER THREW AN ERROR !!!"
|
23
|
+
Faktory.logger.error ex
|
24
|
+
Faktory.logger.error ex.backtrace.join("\n") unless ex.backtrace.nil?
|
27
25
|
end
|
28
26
|
end
|
29
|
-
|
30
27
|
end
|
31
28
|
end
|
data/lib/faktory/fetch.rb
CHANGED
@@ -3,15 +3,15 @@
|
|
3
3
|
module Faktory
|
4
4
|
UnitOfWork = Struct.new(:job) do
|
5
5
|
def acknowledge
|
6
|
-
Faktory.server {|c| c.ack(jid) }
|
6
|
+
Faktory.server { |c| c.ack(jid) }
|
7
7
|
end
|
8
8
|
|
9
9
|
def fail(ex)
|
10
|
-
Faktory.server {|c| c.fail(jid, ex) }
|
10
|
+
Faktory.server { |c| c.fail(jid, ex) }
|
11
11
|
end
|
12
12
|
|
13
13
|
def jid
|
14
|
-
job[
|
14
|
+
job["jid"]
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
@@ -39,6 +39,5 @@ module Faktory
|
|
39
39
|
@queues.shuffle.uniq
|
40
40
|
end
|
41
41
|
end
|
42
|
-
|
43
42
|
end
|
44
43
|
end
|
data/lib/faktory/io.rb
CHANGED
@@ -14,7 +14,7 @@ module Faktory
|
|
14
14
|
# We have to implement them ourselves by using
|
15
15
|
# nonblocking IO and IO.select.
|
16
16
|
def initialize(**opts)
|
17
|
-
@buf = ""
|
17
|
+
@buf = +""
|
18
18
|
@timeout = opts[:timeout] || 5
|
19
19
|
end
|
20
20
|
|
@@ -33,6 +33,7 @@ module Faktory
|
|
33
33
|
end
|
34
34
|
|
35
35
|
private
|
36
|
+
|
36
37
|
def read_timeout(nbytes)
|
37
38
|
loop do
|
38
39
|
result = @sock.read_nonblock(nbytes, exception: false)
|
@@ -40,7 +41,7 @@ module Faktory
|
|
40
41
|
raise Faktory::TimeoutError unless @sock.to_io.wait_readable(@timeout)
|
41
42
|
elsif result == :wait_writable
|
42
43
|
raise Faktory::TimeoutError unless @sock.to_io.wait_writeable(@timeout)
|
43
|
-
elsif result
|
44
|
+
elsif result.nil?
|
44
45
|
raise Errno::ECONNRESET
|
45
46
|
else
|
46
47
|
return result
|
data/lib/faktory/job.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require 'faktory/tracking'
|
3
2
|
|
4
|
-
|
3
|
+
require "faktory/tracking"
|
5
4
|
|
5
|
+
module Faktory
|
6
6
|
##
|
7
7
|
# Include this module in your Job class and you can easily create
|
8
8
|
# asynchronous jobs:
|
@@ -27,7 +27,7 @@ module Faktory
|
|
27
27
|
include Faktory::Trackable
|
28
28
|
|
29
29
|
def self.included(base)
|
30
|
-
raise ArgumentError, "You cannot include Faktory::Job in an ActiveJob: #{base.name}" if base.ancestors.any? {|c| c.name ==
|
30
|
+
raise ArgumentError, "You cannot include Faktory::Job in an ActiveJob: #{base.name}" if base.ancestors.any? { |c| c.name == "ActiveJob::Base" }
|
31
31
|
|
32
32
|
base.extend(ClassMethods)
|
33
33
|
base.faktory_class_attribute :faktory_options_hash
|
@@ -62,7 +62,7 @@ module Faktory
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def perform_async(*args)
|
65
|
-
client_push(@opts.merge(
|
65
|
+
client_push(@opts.merge("args" => args))
|
66
66
|
end
|
67
67
|
|
68
68
|
# +interval+ must be a timestamp, numeric or something that acts
|
@@ -70,13 +70,13 @@ module Faktory
|
|
70
70
|
def perform_in(interval, *args)
|
71
71
|
int = interval.to_f
|
72
72
|
now = Time.now.to_f
|
73
|
-
ts = (int < 1_000_000_000 ? now + int : int)
|
73
|
+
ts = ((int < 1_000_000_000) ? now + int : int)
|
74
74
|
at = Time.at(ts).utc.to_datetime.rfc3339(9)
|
75
75
|
|
76
|
-
item = @opts.merge(
|
76
|
+
item = @opts.merge("args" => args, "at" => at)
|
77
77
|
|
78
78
|
# Optimization to enqueue something now that is scheduled to go out now or in the past
|
79
|
-
item.delete(
|
79
|
+
item.delete("at") if ts <= now
|
80
80
|
|
81
81
|
client_push(item)
|
82
82
|
end
|
@@ -107,19 +107,20 @@ module Faktory
|
|
107
107
|
end
|
108
108
|
|
109
109
|
module ClassMethods
|
110
|
-
|
111
110
|
def set(options)
|
112
|
-
|
111
|
+
opts = get_faktory_options.dup
|
112
|
+
opts["jobtype"] = self
|
113
|
+
Setter.new(Util.deep_merge(opts, options))
|
113
114
|
end
|
114
115
|
|
115
116
|
def perform_async(*args)
|
116
|
-
set(
|
117
|
+
set({}).perform_async(*args)
|
117
118
|
end
|
118
119
|
|
119
120
|
# +interval+ must be a timestamp, numeric or something that acts
|
120
121
|
# numeric (like an activesupport time interval).
|
121
122
|
def perform_in(interval, *args)
|
122
|
-
set(
|
123
|
+
set({}).perform_in(interval, *args)
|
123
124
|
end
|
124
125
|
alias_method :perform_at, :perform_in
|
125
126
|
|
@@ -132,9 +133,9 @@ module Faktory
|
|
132
133
|
# backtrace - whether to save the error backtrace in the job payload to display in web UI,
|
133
134
|
# an integer number of lines to save, default *0*
|
134
135
|
#
|
135
|
-
def faktory_options(opts={})
|
136
|
+
def faktory_options(opts = {})
|
136
137
|
# stringify
|
137
|
-
self.faktory_options_hash = get_faktory_options.merge(
|
138
|
+
self.faktory_options_hash = get_faktory_options.merge(opts.map { |k, v| [k.to_s, v] }.to_h)
|
138
139
|
end
|
139
140
|
|
140
141
|
def get_faktory_options # :nodoc:
|
@@ -196,7 +197,6 @@ module Faktory
|
|
196
197
|
end
|
197
198
|
end
|
198
199
|
end
|
199
|
-
|
200
200
|
end
|
201
201
|
|
202
202
|
module Util
|
@@ -215,6 +215,5 @@ module Faktory
|
|
215
215
|
end
|
216
216
|
module_function :deep_merge
|
217
217
|
end
|
218
|
-
|
219
218
|
end
|
220
219
|
end
|
data/lib/faktory/job_logger.rb
CHANGED
data/lib/faktory/launcher.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
|
-
|
2
|
+
|
3
|
+
require "faktory/manager"
|
4
4
|
|
5
5
|
module Faktory
|
6
6
|
class Launcher
|
@@ -22,7 +22,7 @@ module Faktory
|
|
22
22
|
|
23
23
|
# Stops this instance from processing any more jobs,
|
24
24
|
def quiet
|
25
|
-
@current_state =
|
25
|
+
@current_state = "quiet"
|
26
26
|
@manager.quiet
|
27
27
|
end
|
28
28
|
|
@@ -32,17 +32,17 @@ module Faktory
|
|
32
32
|
def stop
|
33
33
|
deadline = Time.now + @options[:timeout]
|
34
34
|
|
35
|
-
@current_state =
|
35
|
+
@current_state = "terminate"
|
36
36
|
@manager.quiet
|
37
37
|
@manager.stop(deadline)
|
38
38
|
end
|
39
39
|
|
40
40
|
def stopping?
|
41
|
-
@current_state ==
|
41
|
+
@current_state == "terminate"
|
42
42
|
end
|
43
43
|
|
44
44
|
def quiet?
|
45
|
-
@current_state ==
|
45
|
+
@current_state == "quiet"
|
46
46
|
end
|
47
47
|
|
48
48
|
PROCTITLES = []
|
@@ -50,28 +50,28 @@ module Faktory
|
|
50
50
|
private unless $TESTING
|
51
51
|
|
52
52
|
def heartbeat
|
53
|
-
title = [
|
53
|
+
title = ["faktory-worker", Faktory::VERSION, @options[:tag]].compact.join(" ")
|
54
54
|
PROCTITLES << proc { title }
|
55
55
|
PROCTITLES << proc { "[#{Processor.busy_count} of #{@options[:concurrency]} busy]" }
|
56
56
|
PROCTITLES << proc { "stopping" if stopping? }
|
57
57
|
PROCTITLES << proc { "quiet" if quiet? }
|
58
58
|
|
59
59
|
loop do
|
60
|
-
$0 = PROCTITLES.map {|p| p.call }.join(" ")
|
60
|
+
$0 = PROCTITLES.map { |p| p.call }.join(" ")
|
61
61
|
|
62
62
|
begin
|
63
|
-
result = Faktory.server {|c| c.beat(@current_state, "rss_kb" => memory_usage(::Process.pid)) }
|
63
|
+
result = Faktory.server { |c| c.beat(@current_state, "rss_kb" => memory_usage(::Process.pid)) }
|
64
64
|
case result
|
65
65
|
when "OK"
|
66
66
|
# all good
|
67
67
|
when "terminate"
|
68
|
-
::Process.kill(
|
68
|
+
::Process.kill("TERM", $$)
|
69
69
|
when "quiet"
|
70
|
-
::Process.kill(
|
70
|
+
::Process.kill("TSTP", $$)
|
71
71
|
else
|
72
72
|
Faktory.logger.warn "Got unexpected BEAT: #{result}"
|
73
73
|
end
|
74
|
-
rescue
|
74
|
+
rescue
|
75
75
|
# best effort, try again in a few secs
|
76
76
|
end
|
77
77
|
sleep 10
|
@@ -97,7 +97,5 @@ module Faktory
|
|
97
97
|
def memory_usage(pid)
|
98
98
|
MEMORY_GRABBER.call(pid)
|
99
99
|
end
|
100
|
-
|
101
|
-
|
102
100
|
end
|
103
101
|
end
|
data/lib/faktory/logging.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
2
|
+
|
3
|
+
require "time"
|
4
|
+
require "logger"
|
5
|
+
require "fcntl"
|
5
6
|
|
6
7
|
module Faktory
|
7
8
|
module Logging
|
8
|
-
|
9
9
|
class Pretty < Logger::Formatter
|
10
10
|
SPACE = " "
|
11
11
|
|
@@ -16,7 +16,7 @@ module Faktory
|
|
16
16
|
|
17
17
|
def context
|
18
18
|
c = Thread.current[:faktory_context]
|
19
|
-
" #{c.join(SPACE)}" if c
|
19
|
+
" #{c.join(SPACE)}" if c&.any?
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -29,8 +29,8 @@ module Faktory
|
|
29
29
|
def self.job_hash_context(job_hash)
|
30
30
|
# If we're using a wrapper class, like ActiveJob, use the "wrapped"
|
31
31
|
# attribute to expose the underlying thing.
|
32
|
-
klass = job_hash.dig(
|
33
|
-
"#{klass} JID-#{job_hash[
|
32
|
+
klass = job_hash.dig("custom", "wrapped") || job_hash["jobtype"]
|
33
|
+
"#{klass} JID-#{job_hash["jid"]}"
|
34
34
|
end
|
35
35
|
|
36
36
|
def self.with_job_hash_context(job_hash, &block)
|
@@ -45,7 +45,7 @@ module Faktory
|
|
45
45
|
Thread.current[:faktory_context].pop
|
46
46
|
end
|
47
47
|
|
48
|
-
def self.initialize_logger(log_target =
|
48
|
+
def self.initialize_logger(log_target = $stdout)
|
49
49
|
oldlogger = defined?(@logger) ? @logger : nil
|
50
50
|
@logger = Logger.new(log_target)
|
51
51
|
@logger.level = Logger::INFO
|
@@ -62,7 +62,7 @@ module Faktory
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def self.logger=(log)
|
65
|
-
@logger = (log
|
65
|
+
@logger = (log || Logger.new(File::NULL))
|
66
66
|
end
|
67
67
|
|
68
68
|
def logger
|
data/lib/faktory/manager.rb
CHANGED
@@ -1,13 +1,11 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
|
-
require 'faktory/util'
|
4
|
-
require 'faktory/processor'
|
5
|
-
require 'faktory/fetch'
|
6
|
-
require 'thread'
|
7
|
-
require 'set'
|
8
2
|
|
9
|
-
|
3
|
+
require "faktory/util"
|
4
|
+
require "faktory/processor"
|
5
|
+
require "faktory/fetch"
|
6
|
+
require "set"
|
10
7
|
|
8
|
+
module Faktory
|
11
9
|
##
|
12
10
|
# The Manager is the central coordination point in Faktory, controlling
|
13
11
|
# the lifecycle of the Processors.
|
@@ -28,7 +26,7 @@ module Faktory
|
|
28
26
|
attr_reader :threads
|
29
27
|
attr_reader :options
|
30
28
|
|
31
|
-
def initialize(options={})
|
29
|
+
def initialize(options = {})
|
32
30
|
logger.debug { options.inspect }
|
33
31
|
@options = options
|
34
32
|
@count = options[:concurrency] || 25
|
@@ -58,7 +56,7 @@ module Faktory
|
|
58
56
|
end
|
59
57
|
|
60
58
|
# hack for quicker development / testing environment
|
61
|
-
PAUSE_TIME =
|
59
|
+
PAUSE_TIME = $stdout.tty? ? 0.1 : 0.5
|
62
60
|
|
63
61
|
def stop(deadline)
|
64
62
|
quiet
|
@@ -114,7 +112,7 @@ module Faktory
|
|
114
112
|
end
|
115
113
|
|
116
114
|
if cleanup.size > 0
|
117
|
-
jobs = cleanup.map {|p| p.job }.compact
|
115
|
+
jobs = cleanup.map { |p| p.job }.compact
|
118
116
|
|
119
117
|
logger.warn { "Terminating #{cleanup.size} busy worker threads" }
|
120
118
|
logger.warn { "Work still in progress #{jobs.inspect}" }
|
@@ -127,6 +125,5 @@ module Faktory
|
|
127
125
|
processor.thread.join(1)
|
128
126
|
end
|
129
127
|
end
|
130
|
-
|
131
128
|
end
|
132
129
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Faktory
|
3
4
|
# Middleware is code configured to run before/after
|
4
5
|
# a job is processed. It is patterned after Rack
|
@@ -106,7 +107,7 @@ module Faktory
|
|
106
107
|
i = entries.index { |entry| entry.klass == newklass }
|
107
108
|
new_entry = i.nil? ? Entry.new(newklass, *args) : entries.delete_at(i)
|
108
109
|
i = entries.index { |entry| entry.klass == oldklass } || entries.count - 1
|
109
|
-
entries.insert(i+1, new_entry)
|
110
|
+
entries.insert(i + 1, new_entry)
|
110
111
|
end
|
111
112
|
|
112
113
|
def exists?(klass)
|
@@ -139,7 +140,7 @@ module Faktory
|
|
139
140
|
|
140
141
|
def initialize(klass, *args)
|
141
142
|
@klass = klass
|
142
|
-
@args
|
143
|
+
@args = args
|
143
144
|
end
|
144
145
|
|
145
146
|
def make_new
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
#
|
3
4
|
# Simple middleware to save the current locale and restore it when the job executes.
|
4
5
|
# Use it by requiring it in your initializer:
|
@@ -11,7 +12,7 @@ module Faktory::Middleware::I18n
|
|
11
12
|
class Client
|
12
13
|
def call(payload, pool)
|
13
14
|
c = payload["custom"] ||= {}
|
14
|
-
c[
|
15
|
+
c["locale"] ||= ::I18n.locale
|
15
16
|
yield
|
16
17
|
end
|
17
18
|
end
|