background_job 0.0.1.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/specs.yml +34 -0
  3. data/.gitignore +11 -0
  4. data/.rspec +1 -0
  5. data/.tool-versions +1 -0
  6. data/CHANGELOG.md +10 -0
  7. data/Gemfile +12 -0
  8. data/Gemfile.lock +58 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +247 -0
  11. data/Rakefile +2 -0
  12. data/background_job.gemspec +39 -0
  13. data/bin/console +14 -0
  14. data/bin/setup +6 -0
  15. data/docker-compose.yml +6 -0
  16. data/lib/background-job.rb +3 -0
  17. data/lib/background_job/configuration/base.rb +102 -0
  18. data/lib/background_job/configuration/faktory.rb +6 -0
  19. data/lib/background_job/configuration/middleware_chain.rb +109 -0
  20. data/lib/background_job/configuration/sidekiq.rb +23 -0
  21. data/lib/background_job/configuration.rb +63 -0
  22. data/lib/background_job/errors.rb +24 -0
  23. data/lib/background_job/jobs/faktory.rb +87 -0
  24. data/lib/background_job/jobs/job.rb +126 -0
  25. data/lib/background_job/jobs/sidekiq.rb +75 -0
  26. data/lib/background_job/jobs.rb +8 -0
  27. data/lib/background_job/lock.rb +141 -0
  28. data/lib/background_job/lock_digest.rb +36 -0
  29. data/lib/background_job/middleware/unique_job/faktory.rb +41 -0
  30. data/lib/background_job/middleware/unique_job/sidekiq.rb +48 -0
  31. data/lib/background_job/middleware/unique_job.rb +67 -0
  32. data/lib/background_job/mixin/faktory.rb +56 -0
  33. data/lib/background_job/mixin/shared_interface.rb +49 -0
  34. data/lib/background_job/mixin/sidekiq.rb +61 -0
  35. data/lib/background_job/mixin.rb +6 -0
  36. data/lib/background_job/redis_pool.rb +28 -0
  37. data/lib/background_job/testing.rb +76 -0
  38. data/lib/background_job/unique_job.rb +84 -0
  39. data/lib/background_job/version.rb +5 -0
  40. data/lib/background_job.rb +87 -0
  41. metadata +131 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7073c14e1fd364a96f5f4ddc812c5d67921905307af97f85bc3d8a0173304093
4
+ data.tar.gz: 95f18748a479ffa52bf39ac94830080564a95223193c8655c59a36083b6eebc7
5
+ SHA512:
6
+ metadata.gz: aa43df351a913191022dc34d5773ec51ab80bfbdf575cad58c1d33845150fa75a443f3e394e00b46da3283f7e0e69a7ed86b4637ef6e2e960ff797021172758f
7
+ data.tar.gz: c78f2257f401f3d9585f210007cb314da943aaa971dd396cccee703e142d1c949e1c037a8fcbb20bb3e8a623b7db0e36b6feb4fd25f1b42338669913465dfe4b
@@ -0,0 +1,34 @@
1
+ name: Specs
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ services:
13
+ redis:
14
+ image: redis
15
+ options: >-
16
+ --health-cmd "redis-cli ping"
17
+ --health-interval 10s
18
+ --health-timeout 5s
19
+ --health-retries 5
20
+ ports:
21
+ - 6379:6379
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+ - name: Set up Ruby
25
+ uses: ruby/setup-ruby@v1
26
+ with:
27
+ ruby-version: 2.7
28
+ bundler-cache: true
29
+ - name: Install dependencies
30
+ run: bundle install
31
+ - name: Run tests
32
+ run: bundle exec rspec
33
+ env:
34
+ REDIS_URL: redis://localhost:6379
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.env
3
+ /.rspec_status
4
+ /.yardoc
5
+ /_yardoc/
6
+ /coverage/
7
+ /doc/
8
+ /pkg/
9
+ /spec/reports/
10
+ /tmp/
11
+ *.gem
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 2.7.8
data/CHANGELOG.md ADDED
@@ -0,0 +1,10 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## 0.0.1 - 2024-08-01
8
+ The first release of the gem
9
+ * Added: Initial implementation with support to Sidekiq and Faktory backends
10
+ * UniqueJob middleware to avoid duplicated jobs
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in 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,58 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ background_job (0.0.1.rc1)
5
+ connection_pool
6
+ multi_json
7
+ redis
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ awesome_print (1.9.2)
13
+ coderay (1.1.3)
14
+ connection_pool (2.4.1)
15
+ diff-lcs (1.5.1)
16
+ dotenv (2.8.1)
17
+ faktory_worker_ruby (2.0.0)
18
+ connection_pool (~> 2.2, >= 2.2.2)
19
+ method_source (1.1.0)
20
+ multi_json (1.15.0)
21
+ pry (0.14.2)
22
+ coderay (~> 1.1)
23
+ method_source (~> 1.0)
24
+ rake (12.3.3)
25
+ redis (5.2.0)
26
+ redis-client (>= 0.22.0)
27
+ redis-client (0.22.2)
28
+ connection_pool
29
+ rspec (3.13.0)
30
+ rspec-core (~> 3.13.0)
31
+ rspec-expectations (~> 3.13.0)
32
+ rspec-mocks (~> 3.13.0)
33
+ rspec-core (3.13.0)
34
+ rspec-support (~> 3.13.0)
35
+ rspec-expectations (3.13.1)
36
+ diff-lcs (>= 1.2.0, < 2.0)
37
+ rspec-support (~> 3.13.0)
38
+ rspec-mocks (3.13.1)
39
+ diff-lcs (>= 1.2.0, < 2.0)
40
+ rspec-support (~> 3.13.0)
41
+ rspec-support (3.13.1)
42
+ timecop (0.9.10)
43
+
44
+ PLATFORMS
45
+ x86_64-linux
46
+
47
+ DEPENDENCIES
48
+ awesome_print
49
+ background_job!
50
+ dotenv
51
+ faktory_worker_ruby
52
+ pry
53
+ rake (~> 12.0)
54
+ rspec
55
+ timecop
56
+
57
+ BUNDLED WITH
58
+ 2.3.22
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 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,247 @@
1
+ # BackgroundJob
2
+
3
+ The purpose of this gem is to provide a simple way to enqueue background jobs in different background job clientes like Sidekiq, Faktory. (More to come). You can push jobs to the clients without actually have the client installed in your system. This is useful for distributed system or data pipelines where you want to use jobs to communicate between different services.
4
+
5
+ If you are using a monolithic application, you should use the client directly. Or in 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.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'background_job'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle install
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install background_job
22
+
23
+ ## Usage
24
+
25
+ Right now the gem supports Sidekiq and Faktory. Client configurations will be covered in the next section.
26
+
27
+ You can build and push jobs using a simple DSL. The DSL is the same for all clients, but the configurations may vary.
28
+
29
+ ```ruby
30
+ # Enqueue the 'Accounts::ConfirmationEmailWorker' job
31
+ # with 'User', 1 arguments to the sidekiq "high_priority_mailing" queue
32
+ # to be executed as soon as possible.
33
+ BackgroundJob.sidekiq("Accounts::ConfirmationEmailWorker", queue: 'high_priority_mailing')
34
+ .with_args("User", 1)
35
+ .push
36
+ ```
37
+
38
+ ```ruby
39
+ # Schedule the 'Accounts::ConfirmationEmailWorker' job
40
+ # with 'User', 1 arguments to the sidekiq "high_priority_mailing" queue
41
+ # to be executed in one hour.
42
+ BackgroundJob.sidekiq("Accounts::ConfirmationEmailWorker", queue: 'high_priority_mailing')
43
+ .with_args("User", 1)
44
+ .in(1.hour)
45
+ .push
46
+ ```
47
+
48
+ ```ruby
49
+ # Enqueue the 'Accounts::ConfirmationEmailWorker' job
50
+ # with 'User', 1 arguments to the faktory "mailing" queue
51
+ # to be executed as soon as possible.
52
+ BackgroundJob.faktory("Accounts::ConfirmationEmailWorker", queue: 'mailing')
53
+ .with_args("User", 1)
54
+ .push
55
+ ```
56
+
57
+ DSL Methods:
58
+ * `with_args(*args)`: Pass the arguments to the job
59
+ * `in(time)`: Schedule the job to be executed in the future. The time can be a `Time`, `DateTime`, `ActiveSupport::Duration` or a number of seconds.
60
+ * `with_job_jid(jid)`: Set the job JID. This is useful to track the job status or cancel it. Optional, it will be generated automatically.
61
+ * `created_at(time)`: Set the job creation time. Optional, it will be generated automatically.
62
+ * `enqueue_at(time)`: Set the job enqueue time. Optional, it will be generated automatically.
63
+ * `push`: Push the job to the client.
64
+
65
+ ### Sidekiq
66
+
67
+ Sidekiq configurations are under a `BackgroundJob.config.sidekiq` config. You must set the `redis` connection where Sidekiq is running.
68
+
69
+ ```ruby
70
+ BackgroundJob.configure do |conf|
71
+ conf.sidekiq.redis = { url: 'redis://localhost:6379/0' } # You can pass the Redis instance directly as well
72
+ # Or using a connection pool
73
+ conf.sidekiq.redis = ConnectionPool.new(size: 5, timeout: 5) do
74
+ Redis.new(url: 'redis://localhost:6379/0')
75
+ end
76
+ # config.sidekiq.namespace = 'sidekiq' # Optional, default is nil in favor of number of databases of Redis
77
+ end
78
+ ```
79
+
80
+ From an YAML file
81
+ ```yaml
82
+ redis:
83
+ url: 'redis://localhost:6379/0'
84
+ jobs:
85
+ UsesJob:
86
+ queue: 'default'
87
+ retry: 3
88
+ BatchImportJob:
89
+ queue: 'import'
90
+ retry: 0
91
+ ```
92
+
93
+ ```ruby
94
+ BackgroundJob.config_for(:sidekiq) do |config|
95
+ config.config_path = 'config/background_job.yml'
96
+ end
97
+ ```
98
+
99
+ #### Client DSL for Sidekiq to enqueue jobs
100
+
101
+ If your are using Sidekiq in a service that does not have a jobs/worker defined, you may want to specify the list of jobs and their configurations like `queue` and `retry` in the `BackgroundJob.config.sidekiq.jobs` configuration.
102
+
103
+ ```ruby
104
+ BackgroundJob.configure do |conf|
105
+ conf.sidekiq.redis = { url: 'redis://localhost:6379/0' }
106
+ conf.sidekiq.jobs = {
107
+ "UsesJob" => { queue: 'default', retry: 3 },
108
+ "BatchImportJob" => { queue: 'import', retry: 0 }
109
+ }
110
+ # Default is true, it means that will raise an error if the job is
111
+ # not specified in the jobs configuration
112
+ #
113
+ # conf.sidekiq.strict = false
114
+ end
115
+ ```
116
+
117
+ #### Backend Mixins for Sidekiq
118
+
119
+ This are optional, you can keep your backend implementation in your application according to the client documentation. But if you want to get benefit of global configurations, or custom middlewares, you can use the provided mixins.
120
+
121
+ ```diff
122
+ class Accounts::ConfirmationEmailWorker
123
+ + extend BackgroundJob.mixin(:sidekiq, queue: :mailing)
124
+ - include Sidekiq::Worker
125
+ - sidekiq_options queue: :mailing
126
+
127
+ def perform(resource_type, resource_id)
128
+ # Do something
129
+ end
130
+ end
131
+ ```
132
+
133
+ 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 with the configurations defined in the mixin and the global configurations.
134
+
135
+ ### Faktory
136
+
137
+ Faktory configurations are under a `BackgroundJob.config.faktory` config. This is in an erly stage. It means that the [faktory_worker_ruby](https://github.com/contribsys/faktory_worker_ruby) gem must be installed in your system.
138
+
139
+ ```ruby
140
+ require 'faktory'
141
+ BackgroundJob.configure do |conf|
142
+ conf.faktory # Just call it to enable the Faktory client
143
+ # Default is true, it means that will raise an error if the job is
144
+ # not specified in the jobs configuration
145
+ #
146
+ # conf.faktory.strict = false
147
+ end
148
+ ```
149
+
150
+ #### Client DSL for Faktory to enqueue jobs
151
+
152
+ If your are using Faktory in a service that does not have a jobs/worker defined, you may want to specify the list of jobs and their configurations like `queue` and `retry` in the `BackgroundJob.config.faktory.jobs` configuration.
153
+
154
+ ```ruby
155
+ BackgroundJob.configure do |conf|
156
+ conf.faktory
157
+ conf.faktory.jobs = {
158
+ "UsesJob" => { queue: 'default', retry: 3 },
159
+ "BatchImportJob" => { queue: 'import', retry: 0 }
160
+ }
161
+ end
162
+ ```
163
+
164
+ #### Backend Mixins for Faktory
165
+
166
+ This are optional, you can keep your backend implementation in your application according to the client documentation. But if you want to get benefit of global configurations, or custom middlewares, you can use the provided mixins.
167
+
168
+ ```diff
169
+ class Accounts::ConfirmationEmailWorker
170
+ + extend BackgroundJob.mixin(:faktory, queue: :mailing)
171
+ - include Faktory::Job
172
+
173
+ def perform(resource_type, resource_id)
174
+ # Do something
175
+ end
176
+ end
177
+ ```
178
+
179
+ 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 with the configurations defined in the mixin and the global configurations.
180
+
181
+ ## Middleware
182
+
183
+ You can define middlewares to run before and after the job execution. This is useful to add custom logging, error handling, or any other custom behavior. The current version implements a UniqueJob middleware that prevents the job to be enqueued if it is already in the queue. More details in the next section.
184
+
185
+ This is an example of a minimal middleware, note the method must return the result or the job will not push the server
186
+
187
+ ```ruby
188
+ class MyMiddleware
189
+ def call(job, conn_pool)
190
+ puts "Before push"
191
+ result = yield
192
+ puts "After push"
193
+ result
194
+ end
195
+ end
196
+
197
+ BackgroundJob.config_for(:sidekiq) do |config|
198
+ config.middleware do |chain|
199
+ chain.add MyMiddleware
200
+ end
201
+ end
202
+ ```
203
+
204
+ ### Unique Jobs
205
+
206
+ 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 loaded by default. You can load this function by require and initialize the `UniqueJob` middleware according to the service(`:faktory` or `:sidekiq`).
207
+
208
+ ```ruby
209
+ require 'background_job/middleware/unique_job'
210
+ BackgroundJob::Middleware::UniqueJob::bootstrap(service: :sidekiq)
211
+ # Or
212
+ BackgroundJob::Middleware::UniqueJob::bootstrap(service: :faktory)
213
+
214
+ # Make sure to add a redis connection to the configuration
215
+ BackgroundJob.configure do |conf|
216
+ conf.redis = { url: 'redis://localhost:6379/0' }
217
+ # Or using a connection pool
218
+ conf.redis = ConnectionPool.new(size: 5, timeout: 5) do
219
+ Redis.new(url: 'redis://localhost:6379/0')
220
+ end
221
+ end
222
+ ```
223
+
224
+ After that just define the `:uniq` settings by worker
225
+
226
+ ```ruby
227
+ BackgroundJob.sidekiq('Mailing::SignUpWorker', uniq: { across: :queue, timeout: 120 })
228
+ .with_args('User', 1)
229
+ .push
230
+ ```
231
+
232
+ You can globally disable/enable this function with the `BackgroundJob.config.sidekiq.unique_job_active = <true|false>`
233
+
234
+ ## Development
235
+
236
+ 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.
237
+
238
+ 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).
239
+
240
+ ## Contributing
241
+
242
+ Bug reports and pull requests are welcome on GitHub at https://github.com/marcosgz/background_job.
243
+
244
+
245
+ ## License
246
+
247
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task default: :spec
@@ -0,0 +1,39 @@
1
+ require_relative 'lib/background_job/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'background_job'
5
+ spec.version = BackgroundJob::VERSION
6
+ spec.authors = ['Marcos G. Zimmermann']
7
+ spec.email = ['mgzmaster@gmail.com']
8
+
9
+ spec.summary = <<~SUMMARY
10
+ A generic swappable background job client.
11
+ SUMMARY
12
+ spec.description = <<~DESCRIPTION
13
+ A generic swappable background job client that allows you to push jobs to different background job services.
14
+ DESCRIPTION
15
+
16
+ spec.homepage = 'https://github.com/marcosgz/background_job'
17
+ spec.license = 'MIT'
18
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0')
19
+
20
+ raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.' unless spec.respond_to?(:metadata)
21
+ spec.metadata['homepage_uri'] = spec.homepage
22
+ spec.metadata['bug_tracker_uri'] = 'https://github.com/marcosgz/background_job/issues'
23
+ spec.metadata['documentation_uri'] = 'https://github.com/marcosgz/background_job'
24
+ spec.metadata['source_code_uri'] = 'https://github.com/marcosgz/background_job'
25
+
26
+ # Specify which files should be added to the gem when it is released.
27
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
28
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
29
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
30
+ end
31
+
32
+ spec.bindir = 'exe'
33
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
34
+ spec.require_paths = ['lib']
35
+
36
+ spec.add_dependency 'redis', '>= 0.0.0'
37
+ spec.add_dependency 'connection_pool', '>= 0.0.0'
38
+ spec.add_dependency 'multi_json', '>= 0.0.0'
39
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'dotenv/load'
5
+ require 'pry'
6
+ require 'awesome_print'
7
+ require 'background_job'
8
+
9
+ BackgroundJob.configure do |config|
10
+ config.faktory.strict = false
11
+ config.sidekiq.strict = false
12
+ end
13
+
14
+ Pry.start
data/bin/setup ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
@@ -0,0 +1,6 @@
1
+ services:
2
+ redis:
3
+ image: redis
4
+ command: redis-server
5
+ ports:
6
+ - 6379:6379
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './background_job'
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ class BackgroundJob::Configuration::Base
4
+ class << self
5
+ private
6
+
7
+ def attribute_accessor(field, validator: nil, normalizer: nil, default: nil, write: true, read: true)
8
+ normalizer ||= :"normalize_#{field}"
9
+ validator ||= :"validate_#{field}"
10
+
11
+ define_method(field) do
12
+ unless instance_variable_defined?(:"@#{field}")
13
+ fallback = config_from_yaml[field.to_s] || default
14
+ return if fallback.nil?
15
+
16
+ send(:"#{field}=", fallback.respond_to?(:call) ? fallback.call : fallback)
17
+ end
18
+ instance_variable_get(:"@#{field}")
19
+ end if read
20
+
21
+ define_method(:"#{field}=") do |value|
22
+ value = send(normalizer, field, value) if respond_to?(normalizer, true)
23
+ send(validator, field, value) if respond_to?(validator, true)
24
+
25
+ instance_variable_set(:"@#{field}", value)
26
+ end if write
27
+ end
28
+ end
29
+
30
+ # Path to the YAML file with configs
31
+ attr_reader :config_path
32
+
33
+ # A Hash with all jobs definitions. The job class name must be the main hash key
34
+ # Example:
35
+ # "FaktoryIndexWorker":
36
+ # retry: false
37
+ # queue: "indexing"
38
+ # adapter: "faktory"
39
+ # "FaktoryBatchIndexWorker":
40
+ # retry: 5
41
+ # queue: "batch_index"
42
+ # adapter: "faktory"
43
+ attribute_accessor :jobs, default: {}
44
+
45
+ # Global disable the unique_job_active
46
+ attribute_accessor :unique_job_active, default: false
47
+ alias unique_job_active? unique_job_active
48
+
49
+ # Does not validate if it's when set to false
50
+ attribute_accessor :strict, default: true
51
+ alias strict? strict
52
+
53
+ def validate_strict_job!(class_name)
54
+ class_name = class_name.to_s
55
+ if strict? && !jobs.key?(class_name)
56
+ raise BackgroundJob::NotDefinedJobError.new(class_name)
57
+ end
58
+ true
59
+ end
60
+
61
+ def config_path=(value)
62
+ @config_from_yaml = nil
63
+ @config_path = value
64
+ end
65
+
66
+ def middleware
67
+ @middleware ||= BackgroundJob::Configuration::MiddlewareChain.new
68
+ yield @middleware if block_given?
69
+ @middleware
70
+ end
71
+
72
+ protected
73
+
74
+ def normalize_jobs(_, value)
75
+ return unless value.is_a?(Hash)
76
+
77
+ hash = {}
78
+ value.each do |class_name, opts|
79
+ hash[class_name.to_s] = deep_symbolize_keys(opts)
80
+ end
81
+ hash
82
+ end
83
+
84
+ def deep_symbolize_keys(hash)
85
+ return hash unless hash.is_a?(Hash)
86
+
87
+ hash.each_with_object({}) do |(key, value), memo|
88
+ memo[key.to_sym] = deep_symbolize_keys(value)
89
+ end
90
+ end
91
+
92
+ def config_from_yaml
93
+ return {} unless config_path
94
+
95
+ @config_from_yaml ||= if File.exist?(config_path)
96
+ YAML.load_file(config_path)
97
+ else
98
+ raise BackgroundJob::InvalidConfigError, "The file #{config_path} does not exist."
99
+ end
100
+ @config_from_yaml || {}
101
+ end
102
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BackgroundJob
4
+ class Configuration::Faktory < Configuration::Base
5
+ end
6
+ end