faktory_worker_ruby 0.7.0 → 1.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.
- checksums.yaml +5 -5
- data/.travis.yml +11 -0
- data/Changes.md +27 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +34 -8
- data/README.md +10 -5
- data/faktory_worker_ruby.gemspec +4 -3
- data/lib/active_job/queue_adapters/faktory_adapter.rb +61 -0
- data/lib/faktory.rb +3 -1
- data/lib/faktory/batch.rb +178 -0
- data/lib/faktory/cli.rb +9 -0
- data/lib/faktory/client.rb +158 -35
- data/lib/faktory/connection.rb +1 -1
- data/lib/faktory/io.rb +51 -0
- data/lib/faktory/job.rb +41 -29
- data/lib/faktory/launcher.rb +20 -5
- data/lib/faktory/logging.rb +2 -2
- data/lib/faktory/manager.rb +3 -0
- data/lib/faktory/middleware/batch.rb +38 -0
- data/lib/faktory/middleware/i18n.rb +2 -4
- data/lib/faktory/mutate.rb +85 -0
- data/lib/faktory/processor.rb +6 -4
- data/lib/faktory/rails.rb +31 -0
- data/lib/faktory/testing.rb +3 -7
- data/lib/faktory/tracking.rb +41 -0
- data/lib/faktory/version.rb +1 -1
- metadata +34 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7739220174ff556abdf6a357cbcd260b6290c732628b27c8dc01ad00be727dd9
|
4
|
+
data.tar.gz: 3c87db6e71078419a761c6b34dbdcdd3914d5551f4b42f04140a1621c6568b50
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b2fc14441abfab58c7cde5401e42adcfe3bb558cd5d5dbf8f6a5db6b176cf2b1d9057370dd0b1daf3d3ca629bb829495bc53167e56e02f0543ec4f89556792ba
|
7
|
+
data.tar.gz: 12b5d2fc13701e3c221b9ef8301bdb5b43806b1058336298393b66fc3f8020eb01d9569a43884a9f789a5df754bd24e987a340a74f12f055ae71a244d0d0763d
|
data/.travis.yml
ADDED
data/Changes.md
CHANGED
@@ -1,5 +1,32 @@
|
|
1
1
|
# Changes
|
2
2
|
|
3
|
+
## 1.0.1
|
4
|
+
|
5
|
+
- Run client middleware before pushing a job to Faktory [#48]
|
6
|
+
- Implement read timeouts for Faktory::Client for faktory#297
|
7
|
+
|
8
|
+
## 1.0.0
|
9
|
+
|
10
|
+
- Ruby 2.5+ is now required
|
11
|
+
- Support for Faktory Enterprise, job batches and job tracking
|
12
|
+
- Support for the MUTATE command.
|
13
|
+
- Notify Faktory when a worker process is going quiet so that the UI shows this
|
14
|
+
- Refactor Faktory::Client error handling for faktory#208
|
15
|
+
|
16
|
+
## 0.8.1
|
17
|
+
|
18
|
+
- Fix breakage with non-ActiveJobs [#29]
|
19
|
+
- Ruby 2.3+ is now required
|
20
|
+
|
21
|
+
## 0.8.0
|
22
|
+
|
23
|
+
- Add `-l LABEL` argument for adding labels to a process [#27, jpwinans]
|
24
|
+
- Support the quiet and shutdown heartbeat signals from the server [#28]
|
25
|
+
|
26
|
+
## 0.7.1
|
27
|
+
|
28
|
+
- Add an ActiveJob adapter for FWR. [#17, jagthedrummer]
|
29
|
+
|
3
30
|
## 0.7.0
|
4
31
|
|
5
32
|
- Add testing API, almost identical to Sidekiq's `sidekiq/testing` API.
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,25 +1,51 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
faktory_worker_ruby (0.
|
5
|
-
connection_pool (~> 2.2, >= 2.2.
|
4
|
+
faktory_worker_ruby (1.0.1)
|
5
|
+
connection_pool (~> 2.2, >= 2.2.2)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
activejob (6.0.3.2)
|
11
|
+
activesupport (= 6.0.3.2)
|
12
|
+
globalid (>= 0.3.6)
|
13
|
+
activesupport (6.0.3.2)
|
14
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
15
|
+
i18n (>= 0.7, < 2)
|
16
|
+
minitest (~> 5.1)
|
17
|
+
tzinfo (~> 1.1)
|
18
|
+
zeitwerk (~> 2.2, >= 2.2.2)
|
19
|
+
concurrent-ruby (1.1.6)
|
20
|
+
connection_pool (2.2.3)
|
21
|
+
docile (1.3.2)
|
22
|
+
globalid (0.4.2)
|
23
|
+
activesupport (>= 4.2.0)
|
24
|
+
i18n (1.8.5)
|
25
|
+
concurrent-ruby (~> 1.0)
|
26
|
+
minitest (5.14.1)
|
27
|
+
minitest-hooks (1.5.0)
|
28
|
+
minitest (> 5.3)
|
29
|
+
rake (13.0.1)
|
30
|
+
simplecov (0.18.5)
|
31
|
+
docile (~> 1.1)
|
32
|
+
simplecov-html (~> 0.11)
|
33
|
+
simplecov-html (0.12.2)
|
34
|
+
thread_safe (0.3.6)
|
35
|
+
tzinfo (1.2.7)
|
36
|
+
thread_safe (~> 0.1)
|
37
|
+
zeitwerk (2.4.0)
|
14
38
|
|
15
39
|
PLATFORMS
|
16
40
|
ruby
|
17
41
|
|
18
42
|
DEPENDENCIES
|
43
|
+
activejob (>= 5.2.0)
|
19
44
|
faktory_worker_ruby!
|
20
45
|
minitest (~> 5)
|
21
46
|
minitest-hooks
|
22
|
-
rake
|
47
|
+
rake
|
48
|
+
simplecov
|
23
49
|
|
24
50
|
BUNDLED WITH
|
25
|
-
1.
|
51
|
+
2.1.4
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# faktory\_worker\_ruby
|
2
2
|
|
3
|
+

|
4
|
+
|
3
5
|
Faktory\_worker\_ruby is the official Ruby client and worker process for the
|
4
6
|
Faktory background job server. It is similar to [Sidekiq](http://sidekiq.org).
|
5
7
|
|
@@ -15,7 +17,7 @@ Faktory background job server. It is similar to [Sidekiq](http://sidekiq.org).
|
|
15
17
|
+-----------------+ +-------------------+
|
16
18
|
| | | |
|
17
19
|
| Client | | Worker |
|
18
|
-
| pushes | |
|
20
|
+
| pushes | | fetches |
|
19
21
|
| jobs | | jobs |
|
20
22
|
| | | |
|
21
23
|
| | | |
|
@@ -30,11 +32,14 @@ Faktory background job server. It is similar to [Sidekiq](http://sidekiq.org).
|
|
30
32
|
This gem contains only the client and worker parts. The
|
31
33
|
server part is [here](https://github.com/contribsys/faktory/)
|
32
34
|
|
33
|
-
##
|
35
|
+
## Requirements
|
34
36
|
|
35
|
-
|
37
|
+
* Ruby 2.5 or higher
|
38
|
+
* Faktory 1.2 or higher [Installation](https://github.com/contribsys/faktory/wiki/Installation)
|
36
39
|
|
37
|
-
|
40
|
+
Optionally, Rails 5.2+ for ActiveJob.
|
41
|
+
|
42
|
+
## Installation
|
38
43
|
|
39
44
|
gem install faktory_worker_ruby
|
40
45
|
|
@@ -92,4 +97,4 @@ PRs to improve this are very welcome).
|
|
92
97
|
|
93
98
|
## Author
|
94
99
|
|
95
|
-
Mike Perham, @
|
100
|
+
Mike Perham, @getajobmike, mike @ contribsys.com
|
data/faktory_worker_ruby.gemspec
CHANGED
@@ -14,10 +14,11 @@ Gem::Specification.new do |gem|
|
|
14
14
|
gem.files = `git ls-files | grep -Ev '^(test|myapp|examples)'`.split("\n")
|
15
15
|
gem.test_files = []
|
16
16
|
gem.version = Faktory::VERSION
|
17
|
-
gem.required_ruby_version = ">= 2.
|
17
|
+
gem.required_ruby_version = ">= 2.5.0"
|
18
18
|
|
19
|
-
gem.add_dependency 'connection_pool', '~> 2.2', ">= 2.2.
|
19
|
+
gem.add_dependency 'connection_pool', '~> 2.2', ">= 2.2.2"
|
20
|
+
gem.add_development_dependency 'activejob', '>= 5.2.0'
|
20
21
|
gem.add_development_dependency 'minitest', '~> 5'
|
21
22
|
gem.add_development_dependency 'minitest-hooks'
|
22
|
-
gem.add_development_dependency 'rake'
|
23
|
+
gem.add_development_dependency 'rake'
|
23
24
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_job'
|
4
|
+
|
5
|
+
module ActiveJob
|
6
|
+
module QueueAdapters
|
7
|
+
# == Faktory adapter for Active Job
|
8
|
+
#
|
9
|
+
# To use Faktory set the queue_adapter config to +:faktory+.
|
10
|
+
#
|
11
|
+
# Rails.application.config.active_job.queue_adapter = :faktory
|
12
|
+
class FaktoryAdapter
|
13
|
+
def enqueue(job) #:nodoc:
|
14
|
+
enqueue_at(job, nil)
|
15
|
+
end
|
16
|
+
|
17
|
+
def enqueue_at(job, timestamp) #:nodoc:
|
18
|
+
jid = SecureRandom.hex(12)
|
19
|
+
job.provider_job_id = jid
|
20
|
+
hash = {
|
21
|
+
"jid" => jid,
|
22
|
+
"jobtype" => JobWrapper.to_s,
|
23
|
+
"custom" => {
|
24
|
+
"wrapped" => job.class.to_s,
|
25
|
+
},
|
26
|
+
"queue" => job.queue_name,
|
27
|
+
"args" => [ job.serialize ],
|
28
|
+
}
|
29
|
+
opts = job.faktory_options_hash.dup
|
30
|
+
hash["at"] = Time.at(timestamp).utc.to_datetime.rfc3339(9) if timestamp
|
31
|
+
if opts.size > 0
|
32
|
+
hash["retry"] = opts.delete("retry") if opts.has_key?("retry")
|
33
|
+
hash["custom"] = opts.merge(hash["custom"])
|
34
|
+
end
|
35
|
+
pool = Thread.current[:faktory_via_pool] || Faktory.server_pool
|
36
|
+
Faktory.client_middleware.invoke(hash, pool) do
|
37
|
+
pool.with do |c|
|
38
|
+
c.push(hash)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class JobWrapper #:nodoc:
|
44
|
+
include Faktory::Job
|
45
|
+
|
46
|
+
def perform(job_data)
|
47
|
+
Base.execute job_data
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class Base
|
54
|
+
class_attribute :faktory_options_hash
|
55
|
+
self.faktory_options_hash = {}
|
56
|
+
|
57
|
+
def self.faktory_options(hsh)
|
58
|
+
self.faktory_options_hash = self.faktory_options_hash.stringify_keys.merge(hsh.stringify_keys)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/faktory.rb
CHANGED
@@ -52,6 +52,7 @@ module Faktory
|
|
52
52
|
# config.worker_middleware do |chain|
|
53
53
|
# chain.add MyServerHook
|
54
54
|
# end
|
55
|
+
# config.default_job_options = { retry: 3 }
|
55
56
|
# end
|
56
57
|
def self.configure_worker
|
57
58
|
yield self if worker?
|
@@ -61,7 +62,7 @@ module Faktory
|
|
61
62
|
# Configuration for Faktory client, use like:
|
62
63
|
#
|
63
64
|
# Faktory.configure_client do |config|
|
64
|
-
# config.
|
65
|
+
# config.default_job_options = { retry: 3 }
|
65
66
|
# end
|
66
67
|
def self.configure_client
|
67
68
|
yield self unless worker?
|
@@ -164,3 +165,4 @@ module Faktory
|
|
164
165
|
end
|
165
166
|
|
166
167
|
require 'faktory/rails' if defined?(::Rails::Engine)
|
168
|
+
require 'faktory/batch'
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require "faktory/middleware/batch"
|
2
|
+
|
3
|
+
module Faktory
|
4
|
+
##
|
5
|
+
# A Batch is a set of jobs which can be tracked as a group, with
|
6
|
+
# callbacks that can fire after all the jobs are attempted or successful.
|
7
|
+
# Every batch must define at least one callback.
|
8
|
+
#
|
9
|
+
# * The "complete" callback is fired when all jobs in the batch have been attempted.
|
10
|
+
# Some might have failed.
|
11
|
+
# * The "success" callback is fired when all jobs in the batch have succeeded. This
|
12
|
+
# might never be fired if a job continues to error until it runs out of retries.
|
13
|
+
#
|
14
|
+
# **Please note that batches are only available in Faktory Enterprise.** This is
|
15
|
+
# the client-side code required to implement batches, it won't work without
|
16
|
+
# the server-side component.
|
17
|
+
#
|
18
|
+
# Simple example:
|
19
|
+
#
|
20
|
+
# b = Faktory::Batch.new
|
21
|
+
# b.description = "Process all documents for user 12345"
|
22
|
+
# # a callback can be defined as just a Ruby job class
|
23
|
+
# b.success = "MySuccessCallbackJob"
|
24
|
+
# # or the full job hash...
|
25
|
+
# b.complete = { jobtype: "MyCompleteCallbackJob", args: [12345], queue: "critical" }
|
26
|
+
# b.jobs do
|
27
|
+
# SomeJob.perform_async(xyz)
|
28
|
+
# AnotherJob.perform_async(user_id)
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# At the end of the `jobs` call, the batch is persisted to the Faktory server. It must
|
32
|
+
# not be modified further with one exception: jobs within the batch can "reopen" the batch
|
33
|
+
# in order to dynamically add more jobs or child batches.
|
34
|
+
#
|
35
|
+
# Any job within a batch may "reopen" its own batch to dynamically add more jobs.
|
36
|
+
# A job can get access to its batch by using the `bid` or `batch` accessor on
|
37
|
+
# `Faktory::Job`. You can use the `bid` accessor to test if the job is part of a batch.
|
38
|
+
#
|
39
|
+
# Reopen example:
|
40
|
+
#
|
41
|
+
# class MyJob
|
42
|
+
# include Faktory::Job
|
43
|
+
#
|
44
|
+
# def perform
|
45
|
+
# batch.jobs do
|
46
|
+
# SomeOtherJob.perform_async
|
47
|
+
# end if bid
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# Batches may be nested without limit by setting `parent_bid` when creating a
|
51
|
+
# batch. Generally you create child batches if you wish that subset of jobs to have
|
52
|
+
# their own callback for your application logic purposes. Otherwise you can reopen the
|
53
|
+
# current batch and add more jobs.
|
54
|
+
#
|
55
|
+
# Batch parent/child relationship is never implicit: you must manually set
|
56
|
+
# `parent_bid` if you wish to define a child batch.
|
57
|
+
#
|
58
|
+
# Nested example:
|
59
|
+
#
|
60
|
+
# class MyJob
|
61
|
+
# include Faktory::Job
|
62
|
+
#
|
63
|
+
# def perform
|
64
|
+
# child = Faktory::Batch.new
|
65
|
+
#
|
66
|
+
# # MyJob is executing as part of a previously defined batch.
|
67
|
+
# # Add a new child batch to this batch.
|
68
|
+
# child.parent_bid = bid
|
69
|
+
# child.success = ...
|
70
|
+
# child.jobs do |cb|
|
71
|
+
# SomeJob.perform_async
|
72
|
+
#
|
73
|
+
# gchild = Faktory::Batch.new
|
74
|
+
# gchild.parent_bid = cb.bid
|
75
|
+
# gchild.success = ...
|
76
|
+
# gchild.jobs do |gcb|
|
77
|
+
# ChildJob.perform_async
|
78
|
+
# end
|
79
|
+
# end
|
80
|
+
# end
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# Callbacks are guaranteed to be called hierarchically: child's success callback
|
84
|
+
# will not be called until gchild's success callback has executed successfully.
|
85
|
+
#
|
86
|
+
class Batch
|
87
|
+
attr_reader :bid
|
88
|
+
attr_accessor :description, :parent_bid
|
89
|
+
|
90
|
+
def initialize(bid=nil)
|
91
|
+
@bid = bid
|
92
|
+
end
|
93
|
+
|
94
|
+
def success=(val)
|
95
|
+
raise "Batch cannot be modified once created" if bid
|
96
|
+
@success = to_callback(val)
|
97
|
+
end
|
98
|
+
|
99
|
+
def complete=(val)
|
100
|
+
raise "Batch cannot be modified once created" if bid
|
101
|
+
@success = to_callback(val)
|
102
|
+
end
|
103
|
+
|
104
|
+
def jobs(&block)
|
105
|
+
Faktory.server do |client|
|
106
|
+
if @bid.nil?
|
107
|
+
@bid = client.create_batch(self, &block)
|
108
|
+
else
|
109
|
+
client.reopen_batch(self, &block)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def to_h
|
115
|
+
raise ArgumentError, "Callback required" unless defined?(@success) || defined?(@complete)
|
116
|
+
|
117
|
+
hash = {}
|
118
|
+
hash["parent_bid"] = parent_bid if parent_bid
|
119
|
+
hash["description"] = description if description
|
120
|
+
hash["success"] = @success if defined?(@success)
|
121
|
+
hash["complete"] = @complete if defined?(@complete)
|
122
|
+
hash
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
def to_callback(val)
|
128
|
+
case val
|
129
|
+
when String
|
130
|
+
basic_job.merge({ "jobtype" => val })
|
131
|
+
when Class
|
132
|
+
basic_job.merge({ "jobtype" => val })
|
133
|
+
when Hash
|
134
|
+
basic_job.merge(val)
|
135
|
+
else
|
136
|
+
raise ArgumentError, "Unknown callback #{val}"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def basic_job
|
141
|
+
{
|
142
|
+
"jid" => SecureRandom.hex(12),
|
143
|
+
"args" => [],
|
144
|
+
"queue" => "default",
|
145
|
+
}
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
class BatchStatus
|
150
|
+
def initialize(bid)
|
151
|
+
@bid = bid
|
152
|
+
end
|
153
|
+
|
154
|
+
def hash
|
155
|
+
@hash ||= Faktory.server{|c| c.batch_status(@bid) }
|
156
|
+
end
|
157
|
+
|
158
|
+
def created_at
|
159
|
+
hash["created_at"]
|
160
|
+
end
|
161
|
+
|
162
|
+
def description
|
163
|
+
hash["description"]
|
164
|
+
end
|
165
|
+
|
166
|
+
def parent_bid
|
167
|
+
hash["parent_bid"]
|
168
|
+
end
|
169
|
+
|
170
|
+
def total
|
171
|
+
hash["total"]
|
172
|
+
end
|
173
|
+
|
174
|
+
def pending
|
175
|
+
hash["pending"]
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|