gouda 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +15 -9
- data/.gitignore +2 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +8 -1
- data/README.md +90 -1
- data/gouda.gemspec +2 -2
- data/lib/gouda/active_job_extensions/concurrency.rb +1 -1
- data/lib/gouda/railtie.rb +3 -2
- data/lib/gouda/scheduler.rb +47 -3
- data/lib/gouda/version.rb +1 -1
- data/lib/gouda/worker.rb +1 -1
- data/lib/gouda/workload.rb +3 -3
- data/lib/gouda.rb +2 -2
- data/tmp/.keep +0 -0
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0fa853c78222eb23897ccb31ed465fc231aa5894641fe0d1991ade90a5e3fc8d
|
4
|
+
data.tar.gz: e9680b441d3fe9c3da7fadf50272c033db712296104870d016b278da2c1d92bd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9a64544cd45d14400ab949a848e0325ee5d5305d648f7f38239279f93e1f8d2d32dac368708317aafbf470b48e16f88a0ffe4bad6890798ef53adea0566da5f6
|
7
|
+
data.tar.gz: e2140d4da50c4afe8edadd51bb3049b60935e4c0273d235dcb1988efa2900362ea81451a58df04ba3f4db58209380ea9a58ccedd42972806bd5be2cd9f19d7d4
|
data/.github/workflows/ci.yml
CHANGED
@@ -9,28 +9,34 @@ env:
|
|
9
9
|
jobs:
|
10
10
|
test:
|
11
11
|
name: Tests
|
12
|
-
runs-on: ubuntu-
|
12
|
+
runs-on: ubuntu-22.04
|
13
|
+
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
|
14
|
+
strategy:
|
15
|
+
matrix:
|
16
|
+
ruby:
|
17
|
+
- '2.7'
|
18
|
+
- '3.3'
|
13
19
|
services:
|
14
20
|
postgres:
|
15
|
-
image: postgres
|
21
|
+
image: postgres
|
16
22
|
env:
|
17
23
|
POSTGRES_PASSWORD: postgres
|
24
|
+
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
|
18
25
|
ports:
|
19
26
|
- 5432:5432
|
20
|
-
options: >-
|
21
|
-
--health-cmd pg_isready
|
22
|
-
--health-interval 100ms
|
23
|
-
--health-timeout 1s
|
24
|
-
--health-retries 100
|
25
27
|
|
26
|
-
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
|
27
28
|
steps:
|
28
29
|
- name: Checkout
|
29
30
|
uses: actions/checkout@v4
|
30
31
|
- name: Setup Ruby
|
31
32
|
uses: ruby/setup-ruby@v1
|
32
33
|
with:
|
33
|
-
ruby-version:
|
34
|
+
ruby-version: ${{ matrix.ruby }}
|
34
35
|
bundler-cache: true
|
35
36
|
- name: "Tests and Lint"
|
36
37
|
run: bundle exec rake
|
38
|
+
env:
|
39
|
+
PGHOST: localhost
|
40
|
+
PGUSER: postgres
|
41
|
+
PGPASSWORD: postgres
|
42
|
+
TESTOPTS: "--fail-fast"
|
data/.gitignore
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.
|
1
|
+
3.3.1
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
-
## [0.1.0] - 2023-
|
3
|
+
## [0.1.0] - 2023-06-10
|
4
4
|
|
5
5
|
- Initial release
|
6
6
|
|
7
|
+
## [0.1.1] - 2023-06-10
|
8
|
+
|
9
|
+
- Fix support for older ruby versions until 2.7
|
10
|
+
|
11
|
+
## [0.1.2] - 2023-06-11
|
12
|
+
|
13
|
+
- Updated readme and method renaming in Scheduler
|
data/README.md
CHANGED
@@ -11,7 +11,96 @@ $ bundle install
|
|
11
11
|
$ bin/rails g gouda:install
|
12
12
|
```
|
13
13
|
|
14
|
-
|
14
|
+
Gouda is build as a lightweight alternative to [good_job](https://github.com/bensheldon/good_job) and has been created before [solid_queue.](https://github.com/rails/solid_queue/)
|
15
|
+
It is _smaller_ than solid_queue though.
|
16
|
+
|
17
|
+
It was designed to enable job processing using `SELECT ... FOR UPDATE SKIP LOCKED` on Postgres so that we could use pg_bouncer in our system setup.
|
18
|
+
|
19
|
+
|
20
|
+
## Key concepts in Gouda: Workload
|
21
|
+
|
22
|
+
Gouda is built around the concept of a **Workload.** A workload is not the same as an ActiveJob. A workload is a single execution of a task - the task may be an entire ActiveJob, or a retry of an ActiveJob, or a part of a sequence of ActiveJobs initiated using [job-iteration](https://github.com/shopify/job-iteration)
|
23
|
+
|
24
|
+
You can easily have multiple `Workloads` stored in your queue which reference the same job. However, when you are using Gouda it is important to always keep the distinction between the two in mind.
|
25
|
+
|
26
|
+
When an ActiveJob gets first initialised, it receives a randomly-generated ActiveJob ID, which is normally a UUID. This UUID will be reused when a job gets retried, or when job-iteration is in use - but it will exist across multiple Gouda workloads.
|
27
|
+
|
28
|
+
A `Workload` can only be in one of the three states: `enqueued`, `executing` and `finished`. It does not matter whether the workload has raised an exception, or was manually canceled before it started performing, or succeeded - its terminal state is always going to be `finished`, regardless. This is done on purpose: Gouda uses a number of partial indexes in Postgres which allows it to maintain uniqueness, but only among jobs which are either waiting to start or already running. Additionally, _only the transitions between those states_ are guarded by `BEGIN...COMMIT` and it is the selection on those states that is supplemented by `SELECT ... FOR UPDATE SKIP LOCKED`. The only time locks are placed on a particular `gouda_workloads` row is when this update is about to take place (`SELECT` then `UPDATE`). This makes Gouda a good fit for use with pg_bouncer in transaction mode.
|
29
|
+
|
30
|
+
Understanding workload identity is key for making good use of Gouda. For example, an ActiveJob that gets retried can take the following shape in Gouda:
|
31
|
+
|
32
|
+
```
|
33
|
+
____________________________ _______________________________________________
|
34
|
+
| ActiveJob(id="0abc-...34") | ----> | Workload(id="f67b-...123",state="finished") |
|
35
|
+
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
36
|
+
____________________________ _______________________________________________
|
37
|
+
| ActiveJob(id="0abc-...34") | ----> | Workload(id="5e52-...456",state="finished") |
|
38
|
+
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
39
|
+
____________________________ _______________________________________________
|
40
|
+
| ActiveJob(id="0abc-...34") | ----> | Workload(id="8a41-...789",state="enqueued") |
|
41
|
+
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
42
|
+
```
|
43
|
+
|
44
|
+
This would happen if, for example, the ActiveJob raises an exception inside `perform` and is configured to `retry_on` after this exception. Same for job-iteration:
|
45
|
+
|
46
|
+
```
|
47
|
+
_______________________________________ _______________________________________________
|
48
|
+
| ActiveJob(id="0abc-...34",cursor=nil) | ----> | Workload(id="f67b-...123",state="finished") |
|
49
|
+
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
50
|
+
_______________________________________ _______________________________________________
|
51
|
+
| ActiveJob(id="0abc-...34",cursor=123) | ----> | Workload(id="5e52-...456",state="finished") |
|
52
|
+
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
53
|
+
_______________________________________ _______________________________________________
|
54
|
+
| ActiveJob(id="0abc-...34",cursor=456) | ----> | Workload(id="8a41-...789",state="executing") |
|
55
|
+
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
56
|
+
```
|
57
|
+
|
58
|
+
A key thing to remember when reading the Gouda source code is that **workloads and jobs are not the same thing.** A single job **may span multiple workloads.**
|
59
|
+
|
60
|
+
## Key concepts in Gouda: concurrency keys
|
61
|
+
|
62
|
+
Gouda has a few indexes on the `gouda_workloads` table which will:
|
63
|
+
|
64
|
+
* Forbid inserting another `enqueued` workload with the same `enqueue_concurrency_key` value. Uniqueness is on that column only.
|
65
|
+
* Forbid a workload from transition into `executing` when another workload with the same `execution_concurrency_key` is already running.
|
66
|
+
|
67
|
+
These are compatible with good_job concurrency keys, with one major distinction: we use unique indices and not counters, so these keys can be used
|
68
|
+
to **prevent concurrent executions** but not to **limit the load on the system**, and the limit of 1 is always enforced.
|
69
|
+
|
70
|
+
## Key concepts in Gouda: `executing_on`
|
71
|
+
|
72
|
+
A `Workload` is executing on a particular `executing_on` entity - usually a worker thread. That entity gets a pseudorandom ID . The `executing_on` value can be used to see, for example, whether a particular worker thread has hung. If multiple jobs have a far-behind `updated_at` and are all `executing`, this likely means that the worker has crashed or hung. The value can also be used to build a table of currently running workers.
|
73
|
+
|
74
|
+
## Usage tips: bulkify your enqueues
|
75
|
+
|
76
|
+
When possible, Gouda uses `enqueue_all` to `INSERT` as many jobs at once as possible. With modern servers this allows for very rapid insertion of very large
|
77
|
+
batches of jobs. It is supplemented by a module which will make all `perform_later` calls buffered and submitted to the queue in bulk:
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
Gouda.in_bulk do
|
81
|
+
User.joined_recently.find_each do |user|
|
82
|
+
WelcomeMailer.with(user:).welcome_email.deliver_later
|
83
|
+
end
|
84
|
+
end
|
85
|
+
```
|
86
|
+
|
87
|
+
If there are multiple ActiveJob adapters configured and you bulk-enqueue a job which uses an adapter different than Gouda, `in_bulk` will try to use `enqueue_all` on that
|
88
|
+
adapter as well.
|
89
|
+
|
90
|
+
## Usage tips: co-commit
|
91
|
+
|
92
|
+
Gouda is designed to `COMMIT` the workload together with your business data. It does not need `after_commit` unless you so choose. In fact,
|
93
|
+
the main advantage of DB-based job queues such as Gouda is that you can always rely on the fact that the workload will be enqueued only
|
94
|
+
once the data it needs to operate on is already available for reading. This is guaranteed to work:
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
User.transaction do
|
98
|
+
freshly_joined_user = User.create!(user_params)
|
99
|
+
WelcomeMailer.with(user: freshly_joined_user).welcome_email.deliver_later
|
100
|
+
end
|
101
|
+
```
|
102
|
+
|
103
|
+
## Web UI
|
15
104
|
|
16
105
|
At the moment the Gouda UI is proprietary, so this gem only provides a "headless" implementation. We expect this to change in the future.
|
17
106
|
|
data/gouda.gemspec
CHANGED
@@ -4,12 +4,12 @@ Gem::Specification.new do |spec|
|
|
4
4
|
spec.name = "gouda"
|
5
5
|
spec.version = Gouda::VERSION
|
6
6
|
spec.summary = "Job Scheduler"
|
7
|
-
spec.description = "Job Scheduler for Rails"
|
7
|
+
spec.description = "Job Scheduler for Rails and PostgreSQL"
|
8
8
|
spec.authors = ["Sebastian van Hesteren", "Julik Tarkhanov"]
|
9
9
|
spec.email = ["sebastian@cheddar.me", "me@julik.nl"]
|
10
10
|
spec.homepage = "https://rubygems.org/gems/gouda"
|
11
11
|
spec.license = "MIT"
|
12
|
-
spec.required_ruby_version = Gem::Requirement.new(">= 2.
|
12
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
|
13
13
|
spec.require_paths = ["lib"]
|
14
14
|
|
15
15
|
spec.metadata["homepage_uri"] = spec.homepage
|
data/lib/gouda/railtie.rb
CHANGED
@@ -34,8 +34,6 @@ module Gouda
|
|
34
34
|
# The `to_prepare` block which is executed once in production
|
35
35
|
# and before each request in development.
|
36
36
|
config.to_prepare do
|
37
|
-
Gouda::Scheduler.update_schedule_from_config!
|
38
|
-
|
39
37
|
if defined?(Rails) && Rails.respond_to?(:application)
|
40
38
|
config_from_rails = Rails.application.config.try(:gouda)
|
41
39
|
if config_from_rails
|
@@ -52,6 +50,9 @@ module Gouda
|
|
52
50
|
Gouda.config.polling_sleep_interval_seconds = 0.2
|
53
51
|
Gouda.config.logger.level = Gouda.config.log_level
|
54
52
|
end
|
53
|
+
|
54
|
+
Gouda::Scheduler.build_scheduler_entries_list!
|
55
|
+
Gouda::Scheduler.upsert_workloads_from_entries_list!
|
55
56
|
end
|
56
57
|
end
|
57
58
|
end
|
data/lib/gouda/scheduler.rb
CHANGED
@@ -53,7 +53,33 @@ module Gouda::Scheduler
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
-
|
56
|
+
# Takes in a Hash formatted with cron entries in the format similar
|
57
|
+
# to good_job, and builds a table of scheduler entries. A scheduler
|
58
|
+
# entry references a particular job class name, the set of arguments to
|
59
|
+
# be passed to the job when performing it, and either the interval
|
60
|
+
# to repeat the job after or a cron pattern. This method does not
|
61
|
+
# insert the actual Workloads into the database but just builds the
|
62
|
+
# table of the entries. That table gets consulted when workloads finish
|
63
|
+
# to determine whether the workload that just ran was scheduled or ad-hoc,
|
64
|
+
# and whether the subsequent workload has to be enqueued.
|
65
|
+
#
|
66
|
+
# If no table is given the method will attempt to read the table from
|
67
|
+
# Rails application config from `[:gouda][:cron]`.
|
68
|
+
#
|
69
|
+
# The table is a Hash of entries, and the keys are the names of the workload
|
70
|
+
# to be enqueued - those keys are also used to ensure scheduled workloads
|
71
|
+
# only get scheduled once.
|
72
|
+
#
|
73
|
+
# @param cron_table_hash[Hash] a hash of the following shape:
|
74
|
+
# {
|
75
|
+
# download_invoices_every_minute: {
|
76
|
+
# cron: "* * * * *",
|
77
|
+
# class: "DownloadInvoicesJob",
|
78
|
+
# args: ["immediate"]
|
79
|
+
# }
|
80
|
+
# }
|
81
|
+
# @return Array[Entry]
|
82
|
+
def self.build_scheduler_entries_list!(cron_table_hash = nil)
|
57
83
|
Gouda.logger.info "Updating scheduled workload entries..."
|
58
84
|
if cron_table_hash.blank?
|
59
85
|
config_from_rails = Rails.application.config.try(:gouda)
|
@@ -72,10 +98,16 @@ module Gouda::Scheduler
|
|
72
98
|
# `class` is a reserved keyword and a method that exists on every Ruby object so...
|
73
99
|
cron_entry_params[:job_class] ||= cron_entry_params.delete(:class)
|
74
100
|
params_with_defaults = defaults.merge(cron_entry_params)
|
75
|
-
Entry.new(name
|
101
|
+
Entry.new(name: name, **params_with_defaults)
|
76
102
|
end
|
77
103
|
end
|
78
104
|
|
105
|
+
# Once a workload has finished (doesn't matter whether it raised an exception
|
106
|
+
# or completed successfully), it is going to be passed to this method to enqueue
|
107
|
+
# the next scheduled workload
|
108
|
+
#
|
109
|
+
# @param finished_workload[Gouda::Workload]
|
110
|
+
# @return void
|
79
111
|
def self.enqueue_next_scheduled_workload_for(finished_workload)
|
80
112
|
return unless finished_workload.scheduler_key
|
81
113
|
|
@@ -86,11 +118,23 @@ module Gouda::Scheduler
|
|
86
118
|
Gouda.enqueue_jobs_via_their_adapters([timer_entry.build_active_job])
|
87
119
|
end
|
88
120
|
|
121
|
+
# Returns the list of entries of the scheduler which are currently known. Normally the
|
122
|
+
# scheduler will hold the list of entries loaded from the Rails config.
|
123
|
+
#
|
124
|
+
# @return Array[Entry]
|
89
125
|
def self.entries
|
90
126
|
@cron_table || []
|
91
127
|
end
|
92
128
|
|
93
|
-
|
129
|
+
# Will upsert (`INSERT ... ON CONFLICT UPDATE`) workloads for all entries which are in the scheduler entries
|
130
|
+
# table (the table needs to be read or hydrated first using `build_scheduler_entries_list!`). This is done
|
131
|
+
# in a transaction. Any workloads which have been previously inserted from the scheduled entries, but no
|
132
|
+
# longer have a corresponding scheduler entry, will be deleted from the database. If there already are workloads
|
133
|
+
# with the corresponding scheduler key they will not be touched and will be performed with their previously-defined
|
134
|
+
# arguments.
|
135
|
+
#
|
136
|
+
# @return void
|
137
|
+
def self.upsert_workloads_from_entries_list!
|
94
138
|
table_entries = @cron_table || []
|
95
139
|
|
96
140
|
# Remove any cron keyed workloads which no longer match config-wise
|
data/lib/gouda/version.rb
CHANGED
data/lib/gouda/worker.rb
CHANGED
@@ -135,7 +135,7 @@ module Gouda
|
|
135
135
|
break if check_shutdown.call
|
136
136
|
|
137
137
|
did_process = Gouda.config.app_executor.wrap do
|
138
|
-
Gouda::Workload.checkout_and_perform_one(executing_on: worker_id_and_thread_id, queue_constraint
|
138
|
+
Gouda::Workload.checkout_and_perform_one(executing_on: worker_id_and_thread_id, queue_constraint: queue_constraint, in_progress: executing_workload_ids)
|
139
139
|
end
|
140
140
|
|
141
141
|
# If no job was retrieved the queue is likely empty. Relax the polling then and ease off.
|
data/lib/gouda/workload.rb
CHANGED
@@ -66,7 +66,7 @@ class Gouda::Workload < ActiveRecord::Base
|
|
66
66
|
# Appsignal.increment_counter("gouda_workloads_revived", 1, job_class: workload.active_job_class_name)
|
67
67
|
|
68
68
|
interrupted_at = workload.last_execution_heartbeat_at
|
69
|
-
workload.update!(state: "finished", interrupted_at
|
69
|
+
workload.update!(state: "finished", interrupted_at: interrupted_at, last_execution_heartbeat_at: Time.now.utc, execution_finished_at: Time.now.utc)
|
70
70
|
revived_job = ActiveJob::Base.deserialize(workload.active_job_data)
|
71
71
|
# Save the interrupted_at timestamp so that upon execution the new job will raise a Gouda::Interrpupted exception.
|
72
72
|
# The exception can then be handled like any other ActiveJob exception (using rescue_from or similar).
|
@@ -116,7 +116,7 @@ class Gouda::Workload < ActiveRecord::Base
|
|
116
116
|
uncached do # Necessary because we SELECT with a clock_timestamp() which otherwise gets cached by ActiveRecord query cache
|
117
117
|
transaction do
|
118
118
|
jobs.first.tap do |job|
|
119
|
-
job&.update!(state: "executing", executing_on
|
119
|
+
job&.update!(state: "executing", executing_on: executing_on, last_execution_heartbeat_at: Time.now.utc, execution_started_at: Time.now.utc)
|
120
120
|
end
|
121
121
|
rescue ActiveRecord::RecordNotUnique
|
122
122
|
# It can happen that due to a race the `execution_concurrency_key NOT IN` does not capture
|
@@ -133,7 +133,7 @@ class Gouda::Workload < ActiveRecord::Base
|
|
133
133
|
# @param in_progress[#add,#delete] Used for tracking work in progress for heartbeats
|
134
134
|
def self.checkout_and_perform_one(executing_on:, queue_constraint: Gouda::AnyQueue, in_progress: Set.new)
|
135
135
|
# Select a job and mark it as "executing" which will make it unavailable to any other
|
136
|
-
workload = checkout_and_lock_one(executing_on
|
136
|
+
workload = checkout_and_lock_one(executing_on: executing_on, queue_constraint: queue_constraint)
|
137
137
|
if workload
|
138
138
|
in_progress.add(workload.id)
|
139
139
|
workload.perform_and_update_state!
|
data/lib/gouda.rb
CHANGED
@@ -46,7 +46,7 @@ module Gouda
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def self.start
|
49
|
-
Gouda::Scheduler.
|
49
|
+
Gouda::Scheduler.upsert_workloads_from_entries_list!
|
50
50
|
|
51
51
|
queue_constraint = if ENV["GOUDA_QUEUES"]
|
52
52
|
Gouda.parse_queue_constraint(ENV["GOUDA_QUEUES"])
|
@@ -57,7 +57,7 @@ module Gouda
|
|
57
57
|
Gouda.logger.info("Gouda version: #{Gouda::VERSION}")
|
58
58
|
Gouda.logger.info("Worker threads: #{Gouda.config.worker_thread_count}")
|
59
59
|
|
60
|
-
Gouda.worker_loop(n_threads: Gouda.config.worker_thread_count, queue_constraint:)
|
60
|
+
Gouda.worker_loop(n_threads: Gouda.config.worker_thread_count, queue_constraint: queue_constraint)
|
61
61
|
end
|
62
62
|
|
63
63
|
def self.config
|
data/tmp/.keep
ADDED
File without changes
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gouda
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sebastian van Hesteren
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-06-
|
12
|
+
date: 2024-06-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -123,7 +123,7 @@ dependencies:
|
|
123
123
|
- - ">="
|
124
124
|
- !ruby/object:Gem::Version
|
125
125
|
version: '0'
|
126
|
-
description: Job Scheduler for Rails
|
126
|
+
description: Job Scheduler for Rails and PostgreSQL
|
127
127
|
email:
|
128
128
|
- sebastian@cheddar.me
|
129
129
|
- me@julik.nl
|
@@ -157,6 +157,7 @@ files:
|
|
157
157
|
- lib/gouda/version.rb
|
158
158
|
- lib/gouda/worker.rb
|
159
159
|
- lib/gouda/workload.rb
|
160
|
+
- tmp/.keep
|
160
161
|
homepage: https://rubygems.org/gems/gouda
|
161
162
|
licenses:
|
162
163
|
- MIT
|
@@ -172,14 +173,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
172
173
|
requirements:
|
173
174
|
- - ">="
|
174
175
|
- !ruby/object:Gem::Version
|
175
|
-
version: 2.
|
176
|
+
version: 2.7.0
|
176
177
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
177
178
|
requirements:
|
178
179
|
- - ">="
|
179
180
|
- !ruby/object:Gem::Version
|
180
181
|
version: '0'
|
181
182
|
requirements: []
|
182
|
-
rubygems_version: 3.
|
183
|
+
rubygems_version: 3.5.9
|
183
184
|
signing_key:
|
184
185
|
specification_version: 4
|
185
186
|
summary: Job Scheduler
|