multi-background-job 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|