multi-background-job 0.1.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 +7 -0
- data/.github/workflows/specs.yml +35 -0
- data/.gitignore +10 -0
- data/.rspec +1 -0
- data/.tool-versions +1 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +55 -0
- data/LICENSE.txt +21 -0
- data/README.md +137 -0
- data/Rakefile +2 -0
- data/bin/console +13 -0
- data/bin/setup +6 -0
- data/lib/multi-background-job.rb +3 -0
- data/lib/multi_background_job.rb +89 -0
- data/lib/multi_background_job/adapters/adapter.rb +23 -0
- data/lib/multi_background_job/adapters/faktory.rb +111 -0
- data/lib/multi_background_job/adapters/sidekiq.rb +91 -0
- data/lib/multi_background_job/config.rb +152 -0
- data/lib/multi_background_job/errors.rb +25 -0
- data/lib/multi_background_job/lock.rb +137 -0
- data/lib/multi_background_job/lock_digest.rb +39 -0
- data/lib/multi_background_job/middleware/unique_job.rb +69 -0
- data/lib/multi_background_job/middleware/unique_job/faktory.rb +41 -0
- data/lib/multi_background_job/middleware/unique_job/sidekiq.rb +48 -0
- data/lib/multi_background_job/middleware_chain.rb +109 -0
- data/lib/multi_background_job/unique_job.rb +84 -0
- data/lib/multi_background_job/version.rb +5 -0
- data/lib/multi_background_job/worker.rb +114 -0
- data/lib/multi_background_job/workers/faktory.rb +28 -0
- data/lib/multi_background_job/workers/shared_class_methods.rb +26 -0
- data/lib/multi_background_job/workers/sidekiq.rb +28 -0
- data/multi-background-job.gemspec +39 -0
- metadata +122 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 102602d0d8739d98e0baa6a10f9581bb91c4e486ce03ff1d0b3a1448c21756c3
|
4
|
+
data.tar.gz: 8079bfc60fc76222ae8ec886dd8dd076ee17d6903a218afe79c1b6d9cc9c95ac
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5a62442c88fa86368af365c8df9299390ff059994f91bdacfeee9bf8492a495e77951ecb305566d838b50f14d385ed94ee24979d31fb08e2a851ad56578b9f3c
|
7
|
+
data.tar.gz: fb87cf4bcf49808a43766e7c6340d9f24d9eeb4ba1ca15b600a922a80ba89fbab8e62dbc4c48052bb12aed137e7557de40cec5888aabf1480cebc6da23d595ef
|
@@ -0,0 +1,35 @@
|
|
1
|
+
name: Specs
|
2
|
+
on:
|
3
|
+
push:
|
4
|
+
branches: [ master ]
|
5
|
+
pull_request:
|
6
|
+
branches: [ master ]
|
7
|
+
|
8
|
+
jobs:
|
9
|
+
test:
|
10
|
+
runs-on: ubuntu-latest
|
11
|
+
services:
|
12
|
+
redis:
|
13
|
+
image: redis
|
14
|
+
options: >-
|
15
|
+
--health-cmd "redis-cli ping"
|
16
|
+
--health-interval 10s
|
17
|
+
--health-timeout 5s
|
18
|
+
--health-retries 5
|
19
|
+
ports:
|
20
|
+
- 6379:6379
|
21
|
+
steps:
|
22
|
+
- uses: actions/checkout@v2
|
23
|
+
- name: Set up Ruby
|
24
|
+
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
25
|
+
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
26
|
+
# uses: ruby/setup-ruby@v1
|
27
|
+
uses: ruby/setup-ruby@ec106b438a1ff6ff109590de34ddc62c540232e0
|
28
|
+
with:
|
29
|
+
ruby-version: 2.6
|
30
|
+
- name: Install dependencies
|
31
|
+
run: bundle install
|
32
|
+
- name: Run tests
|
33
|
+
run: bundle exec rspec
|
34
|
+
env:
|
35
|
+
REDIS_URL: redis://localhost:6379
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--require spec_helper
|
data/.tool-versions
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby 2.6.3
|
data/Gemfile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in multi-background-job.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
gem 'rake', '~> 12.0'
|
7
|
+
gem 'pry'
|
8
|
+
gem 'awesome_print'
|
9
|
+
gem 'dotenv'
|
10
|
+
gem 'rspec'
|
11
|
+
gem 'timecop'
|
12
|
+
gem 'faktory_worker_ruby', require: false
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
multi-background-job (0.1.0)
|
5
|
+
connection_pool
|
6
|
+
multi_json
|
7
|
+
redis
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
awesome_print (1.8.0)
|
13
|
+
coderay (1.1.3)
|
14
|
+
connection_pool (2.2.3)
|
15
|
+
diff-lcs (1.4.4)
|
16
|
+
dotenv (2.7.6)
|
17
|
+
faktory_worker_ruby (1.0.0)
|
18
|
+
connection_pool (~> 2.2, >= 2.2.2)
|
19
|
+
method_source (1.0.0)
|
20
|
+
multi_json (1.15.0)
|
21
|
+
pry (0.13.1)
|
22
|
+
coderay (~> 1.1)
|
23
|
+
method_source (~> 1.0)
|
24
|
+
rake (12.3.3)
|
25
|
+
redis (4.2.2)
|
26
|
+
rspec (3.9.0)
|
27
|
+
rspec-core (~> 3.9.0)
|
28
|
+
rspec-expectations (~> 3.9.0)
|
29
|
+
rspec-mocks (~> 3.9.0)
|
30
|
+
rspec-core (3.9.3)
|
31
|
+
rspec-support (~> 3.9.3)
|
32
|
+
rspec-expectations (3.9.2)
|
33
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
34
|
+
rspec-support (~> 3.9.0)
|
35
|
+
rspec-mocks (3.9.1)
|
36
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
37
|
+
rspec-support (~> 3.9.0)
|
38
|
+
rspec-support (3.9.3)
|
39
|
+
timecop (0.9.1)
|
40
|
+
|
41
|
+
PLATFORMS
|
42
|
+
ruby
|
43
|
+
|
44
|
+
DEPENDENCIES
|
45
|
+
awesome_print
|
46
|
+
dotenv
|
47
|
+
faktory_worker_ruby
|
48
|
+
multi-background-job!
|
49
|
+
pry
|
50
|
+
rake (~> 12.0)
|
51
|
+
rspec
|
52
|
+
timecop
|
53
|
+
|
54
|
+
BUNDLED WITH
|
55
|
+
2.1.4
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2020 Marcos G. Zimmermann
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
# MultiBackgroundJob
|
2
|
+
|
3
|
+
This library provices an centralized interface to push jobs to a variety of queuing backends. Thus allowing to send jobs to multiple external services. If you are running a [Ruby on Rails](https://github.com/rails/rails) application consider using [Active Jobs](https://github.com/rails/rails/tree/master/activejob). ActiveJobs integrates with a wider range of services and builtin support.
|
4
|
+
|
5
|
+
Supported Services:
|
6
|
+
* Faktory (Faktory::Client is used as depency to push jobs)
|
7
|
+
* Sidekiq (Sidekiq gem is not a depenency. We are using redis connection to push jobs)
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'multi-background-job'
|
15
|
+
```
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle install
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install multi-background-job
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
|
28
|
+
This gem should work with default configurations if you have `REDIS_URL` and/or `FAKTORY_URL` environment variables correctly defined. But you can use the `MultiBackgroundJob#configure` method to customize default settings.
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
MultiBackgroundJob.configure do |config|
|
32
|
+
config.config_path = 'config/background_jobs.yml' # You can use an YAML file. (Default to nil)
|
33
|
+
config.redis_pool_size = 10 # Connection Pool size for redis. (Default to 5)
|
34
|
+
config.redis_pool_timeout = 10 # Connection Pool timeouf for redis. (Default to 5)
|
35
|
+
config.redis_namespace = 'app-name' # The prefix of redis storage keys. (Default to multi-bg)
|
36
|
+
config.redis_config = { path: "/tmp/redis.sock" } # List of configurations to be passed along to the Redis.new. (Default to {})
|
37
|
+
config.workers = { # List of workers and its configurations. (Default to {})
|
38
|
+
'Accounts::ConfirmationEmailWorker' => { retry: 5, queue: 'mailing' },
|
39
|
+
}
|
40
|
+
config.strict = false # Only allow to push jobs to known workers. See `config.workers`. (Default to true)
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
### Client Setup
|
45
|
+
|
46
|
+
You can use the DSL to start building worker and push to background job services.
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
# Enqueue the 'Accounts::ConfirmationEmailWorker' job with 'User', 1 arguments
|
50
|
+
# to the sidekiq "other_mailing" queue
|
51
|
+
MultiBackgroundJob['Accounts::ConfirmationEmailWorker', queue: 'other_mailing' ]
|
52
|
+
.with_args('User', 1)
|
53
|
+
.push(to: :sidekiq)
|
54
|
+
|
55
|
+
# Schedule the 'Accounts::ConfirmationEmailWorker' job with 'User', 1 arguments
|
56
|
+
# to the sidekiq "other_mailing" queue to be executed in one hour.
|
57
|
+
MultiBackgroundJob['Accounts::ConfirmationEmailWorker', queue: 'other_mailing' ]
|
58
|
+
.with_args('User', 1)
|
59
|
+
.in(1.hour)
|
60
|
+
.push(to: :sidekiq)
|
61
|
+
|
62
|
+
# Enqueue the 'Accounts::ConfirmationEmailWorker' job with 'User', 2 arguments
|
63
|
+
# to the faktory "mailing" queue(Using :queu from global config.workers definition)
|
64
|
+
MultiBackgroundJob['Accounts::ConfirmationEmailWorker']
|
65
|
+
.with_args('User', 2)
|
66
|
+
.push(to: :faktory)
|
67
|
+
```
|
68
|
+
|
69
|
+
MultiBackgroundJob is not required as a dependency of backend servers if you are only use it to push jobs(** Except when you are using middleware like **UniqueJobs Middleware** of next section)
|
70
|
+
|
71
|
+
### Server Setup
|
72
|
+
|
73
|
+
This is only a necessary step in the case of using the **UniqueJobs Middleware** of next section.
|
74
|
+
|
75
|
+
Example of sidekiq worker:
|
76
|
+
|
77
|
+
```diff
|
78
|
+
class Accounts::ConfirmationEmailWorker
|
79
|
+
+ extend MultiBackgroundJob.for(:sidekiq, queue: :mailing)
|
80
|
+
- include Sidekiq::Worker
|
81
|
+
- sidekiq_options queue: :mailing
|
82
|
+
|
83
|
+
def perform(resource_type, resource_id); end;
|
84
|
+
end
|
85
|
+
```
|
86
|
+
|
87
|
+
Example of faktory worker:
|
88
|
+
|
89
|
+
```diff
|
90
|
+
class Accounts::ConfirmationEmailWorker
|
91
|
+
+ extend MultiBackgroundJob.for(:sidekiq, queue: :mailing)
|
92
|
+
- include Faktory::Job
|
93
|
+
- faktory_options queue: :mailing
|
94
|
+
|
95
|
+
def perform(resource_type, resource_id); end;
|
96
|
+
end
|
97
|
+
```
|
98
|
+
|
99
|
+
Now when you call `Accounts::ConfirmationEmailWorker.perform_async` or `Accounts::ConfirmationEmailWorker.perform_in` it will use this gem to push jobs to the backend server.
|
100
|
+
|
101
|
+
Note that settings defined througth the worker class have greater weight then the ones defined from global `MultiBackgroundJob.config.workers`. And the `MultiBackgroundJob.config.workers` have greater weight then both `Sidekiq.default_worker_options` or `Faktory.default_job_options`.
|
102
|
+
|
103
|
+
### Unique Jobs
|
104
|
+
|
105
|
+
This library provides one experimental technology to avoid enqueue duplicated jobs. Pro versions of sidekiq and faktory provides this functionality. But this project exposes a mechanism to make this control using `Redis`. It's not required by default. You can load this function by require and initialize the `UniqueJob` middleware according to the service(`:faktory` or `:sidekiq`).
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
require 'multi_background_job/middleware/unique_job'
|
109
|
+
MultiBackgroundJob::Middleware::UniqueJob::bootstrap(service: :sidekiq)
|
110
|
+
# Or
|
111
|
+
MultiBackgroundJob::Middleware::UniqueJob::bootstrap(service: :faktory)
|
112
|
+
```
|
113
|
+
|
114
|
+
After that just define the `:uniq` settings by worker
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
MultiBackgroundJob['Mailing::SignUpWorker', uniq: { across: :queue, timeout: 120 }]
|
118
|
+
.with_args('User', 1)
|
119
|
+
.push(to: :sidekiq)
|
120
|
+
```
|
121
|
+
|
122
|
+
You can globally disable/enable this function with the `MultiBackgroundJob.config.unique_job_active = <true|false>`
|
123
|
+
|
124
|
+
## Development
|
125
|
+
|
126
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
127
|
+
|
128
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
129
|
+
|
130
|
+
## Contributing
|
131
|
+
|
132
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/marcosgz/multi-background-job.
|
133
|
+
|
134
|
+
|
135
|
+
## License
|
136
|
+
|
137
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
data/bin/setup
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
require 'time'
|
5
|
+
require 'securerandom'
|
6
|
+
require 'multi_json'
|
7
|
+
|
8
|
+
require_relative './multi_background_job/version'
|
9
|
+
require_relative 'multi_background_job/errors'
|
10
|
+
require_relative 'multi_background_job/config'
|
11
|
+
require_relative 'multi_background_job/worker'
|
12
|
+
require_relative 'multi_background_job/adapters/adapter'
|
13
|
+
require_relative 'multi_background_job/adapters/sidekiq'
|
14
|
+
require_relative 'multi_background_job/adapters/faktory'
|
15
|
+
|
16
|
+
# This is a central point of our background job queue system.
|
17
|
+
# We have more external services like API and Lme that queue jobs for pipeline processing.
|
18
|
+
# So that way all services can share the same codebase and avoid incompatibility issues
|
19
|
+
#
|
20
|
+
# Example:
|
21
|
+
#
|
22
|
+
# Standard job.
|
23
|
+
# MultiBackgroundJob['UserWorker', queue: 'default']
|
24
|
+
# .with_args(1)
|
25
|
+
# .push(to: :sidekiq)
|
26
|
+
#
|
27
|
+
# Schedule the time when a job will be executed.
|
28
|
+
# MultiBackgroundJob['UserWorker']
|
29
|
+
# .with_args(1)
|
30
|
+
# .at(timestamp)
|
31
|
+
# .push(to: :sidekiq)
|
32
|
+
# MultiBackgroundJob['UserWorker']
|
33
|
+
# .with_args(1)
|
34
|
+
# .in(10.minutes)
|
35
|
+
# .push(to: :sidekiq)
|
36
|
+
#
|
37
|
+
# Unique jobs.
|
38
|
+
# MultiBackgroundJob['UserWorker', uniq: { across: :queue, timeout: 1.minute, unlock_policy: :start }]
|
39
|
+
# .with_args(1)
|
40
|
+
# .push(to: :sidekiq)
|
41
|
+
module MultiBackgroundJob
|
42
|
+
SERVICES = {
|
43
|
+
sidekiq: Adapters::Sidekiq,
|
44
|
+
faktory: Adapters::Faktory,
|
45
|
+
}
|
46
|
+
|
47
|
+
# @param worker_class [String] The worker class name
|
48
|
+
# @param options [Hash] Options that will be passed along to the worker instance
|
49
|
+
# @return [MultiBackgroundJob::Worker] An instance of worker
|
50
|
+
def self.[](worker_class, **options)
|
51
|
+
Worker.new(worker_class, **config.worker_options(worker_class).merge(options))
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.jid
|
55
|
+
SecureRandom.hex(12)
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.for(service, **options)
|
59
|
+
require_relative "multi_background_job/workers/#{service}"
|
60
|
+
service = service.to_sym
|
61
|
+
worker_options = options.merge(service: service)
|
62
|
+
module_name = service.to_s.split(/_/i).collect!{ |w| w.capitalize }.join
|
63
|
+
mod = Workers.const_get(module_name)
|
64
|
+
mod.module_eval do
|
65
|
+
define_method(:bg_worker_options) do
|
66
|
+
worker_options
|
67
|
+
end
|
68
|
+
end
|
69
|
+
mod
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.config
|
73
|
+
@config ||= Config.new
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.configure(&block)
|
77
|
+
return unless block_given?
|
78
|
+
|
79
|
+
config.instance_eval(&block)
|
80
|
+
@redis_pool = nil
|
81
|
+
config
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.redis_pool
|
85
|
+
@redis_pool ||= ConnectionPool.new(config.redis_pool) do
|
86
|
+
Redis.new(config.redis_config)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MultiBackgroundJob
|
4
|
+
module Adapters
|
5
|
+
class Adapter
|
6
|
+
# Push the worker job to the service
|
7
|
+
# @param _worker [MultiBackgroundJob::Worker] An instance of background worker
|
8
|
+
# @abstract Child classes should override this method
|
9
|
+
def self.push(_worker)
|
10
|
+
raise NotImplemented
|
11
|
+
end
|
12
|
+
|
13
|
+
# Coerces the raw payload into an instance of Worker
|
14
|
+
# @param payload [Object] the object that should be coerced to a Worker
|
15
|
+
# @options options [Hash] list of options that will be passed along to the Worker instance
|
16
|
+
# @return [MultiBackgroundJob::Worker] and instance of MultiBackgroundJob::Worker
|
17
|
+
# @abstract Child classes should override this method
|
18
|
+
def self.coerce_to_worker(payload, **options)
|
19
|
+
raise NotImplemented
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MultiBackgroundJob
|
4
|
+
module Adapters
|
5
|
+
# This is a Faktory adapter that converts MultiBackgroundJob::Worker object into a faktory readable format
|
6
|
+
# and then push the jobs into the service.
|
7
|
+
class Faktory < Adapter
|
8
|
+
attr_reader :worker, :queue
|
9
|
+
|
10
|
+
def initialize(worker)
|
11
|
+
@worker = worker
|
12
|
+
@queue = worker.options.fetch(:queue, 'default')
|
13
|
+
|
14
|
+
@payload = worker.payload.merge(
|
15
|
+
'jobtype' => worker.worker_class,
|
16
|
+
'queue' => @queue,
|
17
|
+
'retry' => parse_retry(worker.options[:retry]),
|
18
|
+
)
|
19
|
+
@payload['created_at'] ||= Time.now.to_f
|
20
|
+
end
|
21
|
+
|
22
|
+
# Coerces the raw payload into an instance of Worker
|
23
|
+
# @param payload [Hash] The job as json from redis
|
24
|
+
# @options options [Hash] list of options that will be passed along to the Worker instance
|
25
|
+
# @return [MultiBackgroundJob::Worker] and instance of MultiBackgroundJob::Worker
|
26
|
+
def self.coerce_to_worker(payload, **options)
|
27
|
+
raise(Error, 'invalid payload') unless payload.is_a?(Hash)
|
28
|
+
raise(Error, 'invalid payload') unless payload['jobtype'].is_a?(String)
|
29
|
+
|
30
|
+
options[:retry] ||= payload['retry'] if payload.key?('retry')
|
31
|
+
options[:queue] ||= payload['queue'] if payload.key?('queue')
|
32
|
+
|
33
|
+
MultiBackgroundJob[payload['jobtype'], **options].tap do |worker|
|
34
|
+
worker.with_args(*Array(payload['args'])) if payload.key?('args')
|
35
|
+
worker.with_job_jid(payload['jid']) if payload.key?('jid')
|
36
|
+
worker.created_at(payload['created_at']) if payload.key?('created_at')
|
37
|
+
worker.enqueued_at(payload['enqueued_at']) if payload.key?('enqueued_at')
|
38
|
+
worker.at(payload['at']) if payload.key?('at')
|
39
|
+
worker.unique(payload['uniq']) if payload.key?('uniq')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Initializes adapter and push job into the faktory service
|
44
|
+
#
|
45
|
+
# @param worker [MultiBackgroundJob::Worker] An instance of MultiBackgroundJob::Worker
|
46
|
+
# @return [Hash] Job payload
|
47
|
+
# @see push method for more details
|
48
|
+
def self.push(worker)
|
49
|
+
new(worker).push
|
50
|
+
end
|
51
|
+
|
52
|
+
# Push job to Faktory
|
53
|
+
# * If job has the 'at' key. Then schedule it
|
54
|
+
# * Otherwise enqueue for immediate execution
|
55
|
+
#
|
56
|
+
# @raise [MultiBackgroundJob::Error] raise and error when faktory dependency is not loaded
|
57
|
+
# @return [Hash] Payload that was sent to server
|
58
|
+
def push
|
59
|
+
unless Object.const_defined?(:Faktory)
|
60
|
+
raise MultiBackgroundJob::Error, <<~ERR
|
61
|
+
Faktory client for ruby is not loaded. You must install and require https://github.com/contribsys/faktory_worker_ruby.
|
62
|
+
ERR
|
63
|
+
end
|
64
|
+
@payload['enqueued_at'] ||= Time.now.to_f
|
65
|
+
{'created_at' => false, 'enqueued_at' => false, 'at' => true}.each do |field, past_remove|
|
66
|
+
# Optimization to enqueue something now that is scheduled to go out now or in the past
|
67
|
+
if (time = @payload.delete(field)) &&
|
68
|
+
(!past_remove || (past_remove && time > Time.now.to_f))
|
69
|
+
@payload[field] = parse_time(time)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
pool = Thread.current[:faktory_via_pool] || ::Faktory.server_pool
|
74
|
+
::Faktory.client_middleware.invoke(@payload, pool) do
|
75
|
+
pool.with do |c|
|
76
|
+
c.push(@payload)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
@payload
|
80
|
+
end
|
81
|
+
|
82
|
+
protected
|
83
|
+
|
84
|
+
# Convert worker retry value acording to the Go struct datatype.
|
85
|
+
#
|
86
|
+
# * 25 is the default.
|
87
|
+
# * 0 means the job is completely ephemeral. No matter if it fails or succeeds, it will be discarded.
|
88
|
+
# * -1 means the job will go straight to the Dead set if it fails, no retries.
|
89
|
+
def parse_retry(value)
|
90
|
+
case value
|
91
|
+
when Numeric then value.to_i
|
92
|
+
when false then -1
|
93
|
+
else
|
94
|
+
25
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def parse_time(value)
|
99
|
+
case value
|
100
|
+
when Numeric then Time.at(value).to_datetime.rfc3339(9)
|
101
|
+
when Time then value.to_datetime.rfc3339(9)
|
102
|
+
when DateTime then value.rfc3339(9)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_json(value)
|
107
|
+
MultiJson.dump(value, mode: :compat)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|