kaal 0.3.0 → 0.5.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 +4 -4
- data/README.md +43 -11
- data/lib/kaal/active_record_support.rb +82 -0
- data/lib/kaal/backend/adapter.rb +4 -0
- data/lib/kaal/backend/memory_adapter.rb +5 -0
- data/lib/kaal/backend/mysql.rb +63 -0
- data/lib/kaal/backend/postgres.rb +45 -0
- data/lib/kaal/backend/redis_adapter.rb +5 -0
- data/lib/kaal/backend/sqlite.rb +45 -0
- data/lib/kaal/cli.rb +1 -0
- data/lib/kaal/config/configuration.rb +33 -2
- data/lib/kaal/config/delayed_job_security_policy.rb +60 -0
- data/lib/kaal/config.rb +1 -0
- data/lib/kaal/core/coordinator.rb +68 -19
- data/lib/kaal/definition/database_engine.rb +88 -0
- data/lib/kaal/delayed_job/database_engine.rb +116 -0
- data/lib/kaal/delayed_job/dispatch_failure_logger.rb +31 -0
- data/lib/kaal/delayed_job/memory_engine.rb +79 -0
- data/lib/kaal/delayed_job/mysql_version_support.rb +43 -0
- data/lib/kaal/delayed_job/redis_engine.rb +119 -0
- data/lib/kaal/delayed_job/registry.rb +39 -0
- data/lib/kaal/dispatch/database_engine.rb +120 -0
- data/lib/kaal/internal/active_record/base_record.rb +16 -0
- data/lib/kaal/internal/active_record/connection_support.rb +96 -0
- data/lib/kaal/internal/active_record/database_backend.rb +78 -0
- data/lib/kaal/internal/active_record/definition_record.rb +16 -0
- data/lib/kaal/internal/active_record/definition_registry.rb +81 -0
- data/lib/kaal/internal/active_record/delayed_job_record.rb +16 -0
- data/lib/kaal/internal/active_record/delayed_job_registry.rb +119 -0
- data/lib/kaal/internal/active_record/dispatch_record.rb +16 -0
- data/lib/kaal/internal/active_record/dispatch_registry.rb +100 -0
- data/lib/kaal/internal/active_record/lock_record.rb +16 -0
- data/lib/kaal/internal/active_record/migration_templates.rb +138 -0
- data/lib/kaal/internal/active_record/mysql_backend.rb +89 -0
- data/lib/kaal/internal/active_record/postgres_backend.rb +73 -0
- data/lib/kaal/internal/active_record.rb +19 -0
- data/lib/kaal/internal/sequel/database_backend.rb +79 -0
- data/lib/kaal/internal/sequel/mysql_backend.rb +83 -0
- data/lib/kaal/internal/sequel/postgres_backend.rb +71 -0
- data/lib/kaal/internal/sequel.rb +13 -0
- data/lib/kaal/job_dispatcher.rb +108 -0
- data/lib/kaal/persistence/database.rb +39 -0
- data/lib/kaal/persistence/migration_templates.rb +129 -0
- data/lib/kaal/registry.rb +0 -2
- data/lib/kaal/runtime/scheduler_boot_loader.rb +2 -0
- data/lib/kaal/scheduler_file/job_applier.rb +28 -53
- data/lib/kaal/sequel_support.rb +82 -0
- data/lib/kaal/version.rb +1 -1
- data/lib/kaal.rb +117 -0
- metadata +36 -1
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright Codevedas Inc. 2025-present
|
|
4
|
+
#
|
|
5
|
+
# This source code is licensed under the MIT license found in the
|
|
6
|
+
# LICENSE file in the root directory of this source tree.
|
|
7
|
+
module Kaal
|
|
8
|
+
module Persistence
|
|
9
|
+
# Sequel migration templates emitted by `kaal init`.
|
|
10
|
+
module MigrationTemplates
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
def for_backend(backend)
|
|
14
|
+
backend_name = backend.to_s
|
|
15
|
+
|
|
16
|
+
case backend_name
|
|
17
|
+
when 'sqlite'
|
|
18
|
+
{
|
|
19
|
+
'001_create_kaal_dispatches.rb' => dispatches_template,
|
|
20
|
+
'002_create_kaal_locks.rb' => locks_template,
|
|
21
|
+
'003_create_kaal_definitions.rb' => definitions_template,
|
|
22
|
+
'004_create_kaal_delayed_jobs.rb' => delayed_jobs_template('sqlite')
|
|
23
|
+
}
|
|
24
|
+
when 'postgres', 'mysql'
|
|
25
|
+
{
|
|
26
|
+
'001_create_kaal_dispatches.rb' => dispatches_template,
|
|
27
|
+
'002_create_kaal_definitions.rb' => definitions_template,
|
|
28
|
+
'003_create_kaal_delayed_jobs.rb' => delayed_jobs_template(backend_name)
|
|
29
|
+
}
|
|
30
|
+
else
|
|
31
|
+
{}
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def dispatches_template
|
|
36
|
+
<<~RUBY
|
|
37
|
+
Sequel.migration do
|
|
38
|
+
change do
|
|
39
|
+
create_table?(:kaal_dispatches) do
|
|
40
|
+
primary_key :id
|
|
41
|
+
String :key, null: false
|
|
42
|
+
Time :fire_time, null: false
|
|
43
|
+
Time :dispatched_at, null: false
|
|
44
|
+
String :node_id, null: false
|
|
45
|
+
String :status, null: false, default: 'dispatched', size: 50
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
add_index :kaal_dispatches, [:key, :fire_time], unique: true
|
|
49
|
+
add_index :kaal_dispatches, :key
|
|
50
|
+
add_index :kaal_dispatches, :node_id
|
|
51
|
+
add_index :kaal_dispatches, :status
|
|
52
|
+
add_index :kaal_dispatches, :fire_time
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
RUBY
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def locks_template
|
|
59
|
+
<<~RUBY
|
|
60
|
+
Sequel.migration do
|
|
61
|
+
change do
|
|
62
|
+
create_table?(:kaal_locks) do
|
|
63
|
+
primary_key :id
|
|
64
|
+
String :key, null: false
|
|
65
|
+
Time :acquired_at, null: false
|
|
66
|
+
Time :expires_at, null: false
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
add_index :kaal_locks, :key, unique: true
|
|
70
|
+
add_index :kaal_locks, :expires_at
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
RUBY
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def definitions_template
|
|
77
|
+
<<~RUBY
|
|
78
|
+
Sequel.migration do
|
|
79
|
+
change do
|
|
80
|
+
create_table?(:kaal_definitions) do
|
|
81
|
+
primary_key :id
|
|
82
|
+
String :key, null: false
|
|
83
|
+
String :cron, null: false
|
|
84
|
+
TrueClass :enabled, null: false, default: true
|
|
85
|
+
String :source, null: false
|
|
86
|
+
String :metadata, text: true, null: false, default: '{}'
|
|
87
|
+
Time :disabled_at
|
|
88
|
+
Time :created_at, null: false
|
|
89
|
+
Time :updated_at, null: false
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
add_index :kaal_definitions, :key, unique: true
|
|
93
|
+
add_index :kaal_definitions, :enabled
|
|
94
|
+
add_index :kaal_definitions, :source
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
RUBY
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def delayed_jobs_template(backend)
|
|
101
|
+
args_definition =
|
|
102
|
+
if backend == 'mysql'
|
|
103
|
+
'String :args, text: true, null: false'
|
|
104
|
+
else
|
|
105
|
+
"String :args, text: true, null: false, default: '[]'"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
<<~RUBY
|
|
109
|
+
Sequel.migration do
|
|
110
|
+
change do
|
|
111
|
+
create_table?(:kaal_delayed_jobs) do
|
|
112
|
+
primary_key :id
|
|
113
|
+
String :job_id, null: false
|
|
114
|
+
Time :run_at, null: false
|
|
115
|
+
String :job_class, null: false
|
|
116
|
+
#{args_definition}
|
|
117
|
+
String :queue
|
|
118
|
+
Time :created_at, null: false
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
add_index :kaal_delayed_jobs, :job_id, unique: true
|
|
122
|
+
add_index :kaal_delayed_jobs, :run_at
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
RUBY
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
data/lib/kaal/registry.rb
CHANGED
|
@@ -20,9 +20,7 @@ module Kaal
|
|
|
20
20
|
|
|
21
21
|
##
|
|
22
22
|
# Entry class representing a single registered cron job
|
|
23
|
-
# rubocop:disable Style/RedundantStructKeywordInit
|
|
24
23
|
Entry = Struct.new(:key, :cron, :enqueue, keyword_init: true)
|
|
25
|
-
# rubocop:enable Style/RedundantStructKeywordInit
|
|
26
24
|
|
|
27
25
|
##
|
|
28
26
|
# Initialize a new Registry instance.
|
|
@@ -22,6 +22,8 @@ module Kaal
|
|
|
22
22
|
configuration = fetch_configuration
|
|
23
23
|
return unless configuration
|
|
24
24
|
|
|
25
|
+
Kaal.warn_on_risky_configuration!(configuration:, logger: @logger)
|
|
26
|
+
|
|
25
27
|
return load_scheduler_file if configuration.scheduler_missing_file_policy == :error
|
|
26
28
|
|
|
27
29
|
scheduler_path = configuration.scheduler_config_path.to_s.strip
|
|
@@ -77,7 +77,12 @@ module Kaal
|
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
def resolved_job_class(job_class_name:, key:, queue: nil)
|
|
80
|
-
resolve_job_class(
|
|
80
|
+
Kaal::JobDispatcher.resolve_job_class(
|
|
81
|
+
job_class_name:,
|
|
82
|
+
key:,
|
|
83
|
+
queue:,
|
|
84
|
+
apply_delayed_job_allow_list: false
|
|
85
|
+
)
|
|
81
86
|
end
|
|
82
87
|
|
|
83
88
|
def conflict?(key:, existing_definition:)
|
|
@@ -157,7 +162,7 @@ module Kaal
|
|
|
157
162
|
validate_keyword_keys(raw_kwargs, key)
|
|
158
163
|
|
|
159
164
|
resolved_kwargs = raw_kwargs.transform_keys(&:to_sym)
|
|
160
|
-
dispatch_job(job_class, queue, resolved_args, resolved_kwargs)
|
|
165
|
+
dispatch_job(job_class, queue, resolved_args, resolved_kwargs, key)
|
|
161
166
|
end
|
|
162
167
|
end
|
|
163
168
|
|
|
@@ -178,64 +183,34 @@ module Kaal
|
|
|
178
183
|
nil
|
|
179
184
|
end
|
|
180
185
|
|
|
181
|
-
|
|
182
|
-
normalized_job_class_name = job_class_name.to_s.strip
|
|
183
|
-
raise SchedulerConfigError, "Job class cannot be blank for key '#{key}'" if normalized_job_class_name.empty?
|
|
184
|
-
|
|
185
|
-
error_message = "Unknown job_class #{normalized_job_class_name.inspect} for key '#{key}'"
|
|
186
|
-
job_class = begin
|
|
187
|
-
Kaal::Support::HashTools.constantize(normalized_job_class_name)
|
|
188
|
-
rescue NameError
|
|
189
|
-
nil
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
return validate_dispatch_interface(job_class, key, queue) if job_class
|
|
193
|
-
|
|
194
|
-
raise_unknown_job_class(error_message)
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
private :build_callback, :resolve_job_class
|
|
198
|
-
|
|
199
|
-
def dispatch_job(job_class, queue, args, kwargs)
|
|
200
|
-
job_class_name = job_class.name
|
|
201
|
-
|
|
202
|
-
if queue && !job_class.respond_to?(:set)
|
|
203
|
-
raise SchedulerConfigError,
|
|
204
|
-
"job_class '#{job_class_name}' must respond to .set to use queue #{queue.inspect}"
|
|
205
|
-
end
|
|
186
|
+
private :build_callback
|
|
206
187
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
job_class.perform_later(*args, **kwargs)
|
|
211
|
-
elsif job_class.respond_to?(:perform)
|
|
212
|
-
job_class.perform(*args, **kwargs)
|
|
188
|
+
def dispatch_job(job_class, queue, args, kwargs, key)
|
|
189
|
+
if kwargs.empty?
|
|
190
|
+
Kaal::JobDispatcher.dispatch(job_class:, queue:, args:, key:)
|
|
213
191
|
else
|
|
214
|
-
|
|
215
|
-
"job_class '#{job_class_name}' must respond to .perform, .perform_later, or .set(...).perform_later"
|
|
216
|
-
end
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
def raise_unknown_job_class(error_message)
|
|
220
|
-
raise SchedulerConfigError, error_message
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
def validate_dispatch_interface(job_class, key, queue)
|
|
224
|
-
queue_present = !queue.nil?
|
|
225
|
-
supports_set = job_class.respond_to?(:set)
|
|
226
|
-
supports_perform_later = job_class.respond_to?(:perform_later)
|
|
227
|
-
supports_perform = job_class.respond_to?(:perform)
|
|
192
|
+
job_class_name = job_class.name
|
|
228
193
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
194
|
+
if queue && !job_class.respond_to?(:set)
|
|
195
|
+
raise SchedulerConfigError,
|
|
196
|
+
"job_class '#{job_class_name}' must respond to .set to use queue #{queue.inspect} for scheduler job '#{key}'"
|
|
197
|
+
end
|
|
232
198
|
|
|
233
|
-
|
|
234
|
-
|
|
199
|
+
if queue
|
|
200
|
+
job_class.set(queue: queue).perform_later(*args, **kwargs)
|
|
201
|
+
elsif job_class.respond_to?(:perform_later)
|
|
202
|
+
job_class.perform_later(*args, **kwargs)
|
|
203
|
+
elsif job_class.respond_to?(:perform)
|
|
204
|
+
job_class.perform(*args, **kwargs)
|
|
205
|
+
else
|
|
206
|
+
raise SchedulerConfigError,
|
|
207
|
+
"job_class '#{job_class_name}' must respond to .perform, .perform_later, or .set(...).perform_later for scheduler job '#{key}'"
|
|
208
|
+
end
|
|
209
|
+
end
|
|
235
210
|
end
|
|
236
211
|
|
|
237
212
|
def active_job_dispatch?(job_class, queue)
|
|
238
|
-
|
|
213
|
+
Kaal::JobDispatcher.active_job_dispatch?(job_class, queue)
|
|
239
214
|
end
|
|
240
215
|
end
|
|
241
216
|
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright Codevedas Inc. 2025-present
|
|
4
|
+
#
|
|
5
|
+
# This source code is licensed under the MIT license found in the
|
|
6
|
+
# LICENSE file in the root directory of this source tree.
|
|
7
|
+
require 'fileutils'
|
|
8
|
+
|
|
9
|
+
module Kaal
|
|
10
|
+
# Sequel migration/install support for SQL-backed Kaal backends.
|
|
11
|
+
module Sequel
|
|
12
|
+
module_function
|
|
13
|
+
|
|
14
|
+
def install_postgres_migration(target_dir:, migration_name: 'create_kaal_postgres_backend')
|
|
15
|
+
install_migrations(target_dir:, backend: 'postgres', migration_name:)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def install_mysql_migration(target_dir:, migration_name: 'create_kaal_mysql_backend')
|
|
19
|
+
install_migrations(target_dir:, backend: 'mysql', migration_name:)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def install_sqlite_migration(target_dir:, migration_name: 'create_kaal_sqlite_backend')
|
|
23
|
+
install_migrations(target_dir:, backend: 'sqlite', migration_name:)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def install_migrations(target_dir:, backend:, migration_name: nil)
|
|
27
|
+
require_sequel!
|
|
28
|
+
|
|
29
|
+
normalized_name = normalize_migration_name(migration_name, fallback: default_migration_name_for(backend))
|
|
30
|
+
base_path = File.expand_path(target_dir)
|
|
31
|
+
FileUtils.mkdir_p(base_path)
|
|
32
|
+
|
|
33
|
+
Kaal::Persistence::MigrationTemplates.for_backend(backend).map.with_index do |(_name, contents), index|
|
|
34
|
+
suffix = migration_suffixes_for(backend).fetch(index)
|
|
35
|
+
path = File.expand_path("#{timestamp(index)}_#{normalized_name}_#{suffix}.rb", base_path)
|
|
36
|
+
File.write(path, contents)
|
|
37
|
+
path
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def require_sequel!
|
|
42
|
+
require 'sequel'
|
|
43
|
+
rescue LoadError => e
|
|
44
|
+
raise LoadError,
|
|
45
|
+
"#{e.message}. Add `gem 'sequel'` to your Gemfile to use Sequel-backed Kaal SQL support.",
|
|
46
|
+
cause: e
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def normalize_migration_name(name, fallback:)
|
|
50
|
+
normalized = name.to_s.each_char.with_object(+'') do |char, buffer|
|
|
51
|
+
if letter?(char) || digit?(char)
|
|
52
|
+
buffer << char.downcase
|
|
53
|
+
elsif !buffer.empty? && !buffer.end_with?('_')
|
|
54
|
+
buffer << '_'
|
|
55
|
+
end
|
|
56
|
+
end.delete_suffix('_')
|
|
57
|
+
normalized.empty? ? fallback : normalized
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def default_migration_name_for(backend)
|
|
61
|
+
"create_kaal_#{backend}_backend"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def migration_suffixes_for(backend)
|
|
65
|
+
return %w[dispatches locks definitions delayed_jobs] if backend.to_s == 'sqlite'
|
|
66
|
+
|
|
67
|
+
%w[dispatches definitions delayed_jobs]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def timestamp(offset = 0)
|
|
71
|
+
(Time.now.utc + offset).strftime('%Y%m%d%H%M%S')
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def letter?(char)
|
|
75
|
+
char.between?('a', 'z') || char.between?('A', 'Z')
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def digit?(char)
|
|
79
|
+
char.between?('0', '9')
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
data/lib/kaal/version.rb
CHANGED
data/lib/kaal.rb
CHANGED
|
@@ -10,15 +10,27 @@ require 'kaal/registry'
|
|
|
10
10
|
require 'kaal/dispatch/registry'
|
|
11
11
|
require 'kaal/dispatch/memory_engine'
|
|
12
12
|
require 'kaal/dispatch/redis_engine'
|
|
13
|
+
require 'kaal/delayed_job/registry'
|
|
14
|
+
require 'kaal/delayed_job/memory_engine'
|
|
15
|
+
require 'kaal/delayed_job/redis_engine'
|
|
16
|
+
require 'kaal/delayed_job/dispatch_failure_logger'
|
|
17
|
+
require 'kaal/delayed_job/mysql_version_support'
|
|
13
18
|
require 'kaal/definition/registry'
|
|
14
19
|
require 'kaal/definition/memory_engine'
|
|
15
20
|
require 'kaal/definition/redis_engine'
|
|
16
21
|
require 'kaal/backend/adapter'
|
|
17
22
|
require 'kaal/backend/memory_adapter'
|
|
18
23
|
require 'kaal/backend/redis_adapter'
|
|
24
|
+
require 'kaal/backend/sqlite'
|
|
25
|
+
require 'kaal/backend/postgres'
|
|
26
|
+
require 'kaal/backend/mysql'
|
|
19
27
|
require 'kaal/backend/dispatch_registry_accessor'
|
|
20
28
|
require 'kaal/backend/dispatch_attempt_logger'
|
|
29
|
+
require 'kaal/persistence/migration_templates'
|
|
30
|
+
require 'kaal/sequel_support'
|
|
31
|
+
require 'kaal/active_record_support'
|
|
21
32
|
require 'kaal/utils'
|
|
33
|
+
require 'kaal/job_dispatcher'
|
|
22
34
|
require 'kaal/register_conflict_support'
|
|
23
35
|
require 'kaal/definitions/registry_accessor'
|
|
24
36
|
require 'kaal/definitions/registration_service'
|
|
@@ -50,12 +62,15 @@ module Kaal
|
|
|
50
62
|
@definition_registry = nil
|
|
51
63
|
@definitions_registry_accessor = nil
|
|
52
64
|
@dispatch_registry_accessor = nil
|
|
65
|
+
@risky_configuration_warnings_emitted = {}
|
|
53
66
|
end
|
|
54
67
|
|
|
55
68
|
def reset_registry!
|
|
56
69
|
@registry = Registry.new
|
|
57
70
|
definition_registry = @definition_registry
|
|
58
71
|
definition_registry.clear if definition_registry.respond_to?(:clear)
|
|
72
|
+
delayed_store = configuration.backend&.delayed_store
|
|
73
|
+
delayed_store.clear if delayed_store.respond_to?(:clear)
|
|
59
74
|
@coordinator = nil
|
|
60
75
|
end
|
|
61
76
|
|
|
@@ -78,6 +93,7 @@ module Kaal
|
|
|
78
93
|
end
|
|
79
94
|
|
|
80
95
|
def load_scheduler_file!(runtime_context: RuntimeContext.default)
|
|
96
|
+
warn_on_risky_configuration!
|
|
81
97
|
SchedulerFileLoader.new(
|
|
82
98
|
configuration: configuration,
|
|
83
99
|
definition_registry: definition_registry,
|
|
@@ -113,6 +129,7 @@ module Kaal
|
|
|
113
129
|
end
|
|
114
130
|
|
|
115
131
|
def start!
|
|
132
|
+
warn_on_risky_configuration!
|
|
116
133
|
coordinator.start!
|
|
117
134
|
end
|
|
118
135
|
|
|
@@ -132,6 +149,30 @@ module Kaal
|
|
|
132
149
|
coordinator.tick!
|
|
133
150
|
end
|
|
134
151
|
|
|
152
|
+
# Enqueue a one-off delayed job. Delivery is at-most-once after claim.
|
|
153
|
+
def enqueue_at(at:, job_class:, args:, job_id:, queue: nil, connection: nil)
|
|
154
|
+
delayed_store = delayed_store!
|
|
155
|
+
resolved_run_at = normalize_delayed_run_at(at)
|
|
156
|
+
resolved_args = normalize_delayed_args(args)
|
|
157
|
+
resolved_queue = normalize_delayed_queue(queue)
|
|
158
|
+
resolved_job_id = normalize_delayed_job_id(job_id)
|
|
159
|
+
resolved_job_class = JobDispatcher.resolve_job_class(
|
|
160
|
+
job_class_name: job_class,
|
|
161
|
+
key: resolved_job_id,
|
|
162
|
+
queue: resolved_queue
|
|
163
|
+
)
|
|
164
|
+
resolved_job_class_name = JobDispatcher.normalize_job_class_name(resolved_job_class)
|
|
165
|
+
|
|
166
|
+
delayed_store.enqueue(
|
|
167
|
+
job_id: resolved_job_id,
|
|
168
|
+
run_at: resolved_run_at,
|
|
169
|
+
job_class: resolved_job_class_name,
|
|
170
|
+
args: resolved_args,
|
|
171
|
+
queue: resolved_queue,
|
|
172
|
+
connection: connection
|
|
173
|
+
)
|
|
174
|
+
end
|
|
175
|
+
|
|
135
176
|
def with_idempotency(key, fire_time)
|
|
136
177
|
raise ArgumentError, 'block required' unless block_given?
|
|
137
178
|
|
|
@@ -187,6 +228,14 @@ module Kaal
|
|
|
187
228
|
configuration.time_zone = value
|
|
188
229
|
end
|
|
189
230
|
|
|
231
|
+
def delayed_job_allowed_class_prefixes
|
|
232
|
+
configuration.delayed_job_allowed_class_prefixes
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def delayed_job_allowed_class_prefixes=(value)
|
|
236
|
+
configuration.delayed_job_allowed_class_prefixes = value
|
|
237
|
+
end
|
|
238
|
+
|
|
190
239
|
def definition_registry
|
|
191
240
|
definitions_registry_accessor.call
|
|
192
241
|
end
|
|
@@ -199,6 +248,25 @@ module Kaal
|
|
|
199
248
|
configuration.validate!
|
|
200
249
|
end
|
|
201
250
|
|
|
251
|
+
def validation_warnings
|
|
252
|
+
configuration.validation_warnings
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
def warn_on_risky_configuration!(configuration: self.configuration, logger: configuration.logger)
|
|
256
|
+
warnings = configuration.validation_warnings
|
|
257
|
+
return [] if warnings.empty?
|
|
258
|
+
|
|
259
|
+
@risky_configuration_warnings_emitted ||= {}
|
|
260
|
+
warnings.each do |warning|
|
|
261
|
+
next if @risky_configuration_warnings_emitted[warning]
|
|
262
|
+
|
|
263
|
+
logger&.warn(warning)
|
|
264
|
+
@risky_configuration_warnings_emitted[warning] = true
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
warnings
|
|
268
|
+
end
|
|
269
|
+
|
|
202
270
|
def valid?(expression)
|
|
203
271
|
CronUtils.valid?(expression)
|
|
204
272
|
end
|
|
@@ -247,5 +315,54 @@ module Kaal
|
|
|
247
315
|
def dispatch_registry_accessor
|
|
248
316
|
@dispatch_registry_accessor ||= Backend::DispatchRegistryAccessor.new(configuration: configuration)
|
|
249
317
|
end
|
|
318
|
+
|
|
319
|
+
def delayed_store!
|
|
320
|
+
delayed_store = configuration.backend&.delayed_store
|
|
321
|
+
return delayed_store if delayed_store
|
|
322
|
+
|
|
323
|
+
raise ArgumentError, 'Configured backend does not support delayed jobs'
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def normalize_delayed_run_at(at)
|
|
327
|
+
time = at.is_a?(Time) ? at : at&.to_time
|
|
328
|
+
ensure_delayed_time!(time)
|
|
329
|
+
|
|
330
|
+
time.utc
|
|
331
|
+
rescue NoMethodError
|
|
332
|
+
ensure_delayed_time!(nil)
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
def normalize_delayed_args(args)
|
|
336
|
+
raise ArgumentError, 'args must be an array' unless args.is_a?(Array)
|
|
337
|
+
|
|
338
|
+
args.dup
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
def normalize_delayed_queue(queue)
|
|
342
|
+
case queue
|
|
343
|
+
when nil
|
|
344
|
+
return nil
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
normalized_queue = queue.to_s.strip
|
|
348
|
+
raise ArgumentError, 'queue cannot be blank' if normalized_queue.empty?
|
|
349
|
+
|
|
350
|
+
normalized_queue
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
def normalize_delayed_job_id(job_id)
|
|
354
|
+
normalized_job_id = job_id.to_s.strip
|
|
355
|
+
raise ArgumentError, 'job_id cannot be blank' if normalized_job_id.empty?
|
|
356
|
+
|
|
357
|
+
normalized_job_id
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
def invalid_delayed_time_error
|
|
361
|
+
ArgumentError.new('at must be a Time or time-like value')
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
def ensure_delayed_time!(time)
|
|
365
|
+
raise invalid_delayed_time_error unless time
|
|
366
|
+
end
|
|
250
367
|
end
|
|
251
368
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kaal
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Nitesh Purohit
|
|
@@ -84,30 +84,64 @@ files:
|
|
|
84
84
|
- config/scheduler.yml
|
|
85
85
|
- exe/kaal
|
|
86
86
|
- lib/kaal.rb
|
|
87
|
+
- lib/kaal/active_record_support.rb
|
|
87
88
|
- lib/kaal/backend/adapter.rb
|
|
88
89
|
- lib/kaal/backend/dispatch_attempt_logger.rb
|
|
89
90
|
- lib/kaal/backend/dispatch_logging.rb
|
|
90
91
|
- lib/kaal/backend/dispatch_registry_accessor.rb
|
|
91
92
|
- lib/kaal/backend/memory_adapter.rb
|
|
93
|
+
- lib/kaal/backend/mysql.rb
|
|
94
|
+
- lib/kaal/backend/postgres.rb
|
|
92
95
|
- lib/kaal/backend/redis_adapter.rb
|
|
96
|
+
- lib/kaal/backend/sqlite.rb
|
|
93
97
|
- lib/kaal/cli.rb
|
|
94
98
|
- lib/kaal/config.rb
|
|
95
99
|
- lib/kaal/config/configuration.rb
|
|
100
|
+
- lib/kaal/config/delayed_job_security_policy.rb
|
|
96
101
|
- lib/kaal/config/scheduler_config_error.rb
|
|
97
102
|
- lib/kaal/config/scheduler_time_zone_resolver.rb
|
|
98
103
|
- lib/kaal/core.rb
|
|
99
104
|
- lib/kaal/core/coordinator.rb
|
|
100
105
|
- lib/kaal/core/enabled_entry_enumerator.rb
|
|
101
106
|
- lib/kaal/core/occurrence_finder.rb
|
|
107
|
+
- lib/kaal/definition/database_engine.rb
|
|
102
108
|
- lib/kaal/definition/memory_engine.rb
|
|
103
109
|
- lib/kaal/definition/persistence_helpers.rb
|
|
104
110
|
- lib/kaal/definition/redis_engine.rb
|
|
105
111
|
- lib/kaal/definition/registry.rb
|
|
106
112
|
- lib/kaal/definitions/registration_service.rb
|
|
107
113
|
- lib/kaal/definitions/registry_accessor.rb
|
|
114
|
+
- lib/kaal/delayed_job/database_engine.rb
|
|
115
|
+
- lib/kaal/delayed_job/dispatch_failure_logger.rb
|
|
116
|
+
- lib/kaal/delayed_job/memory_engine.rb
|
|
117
|
+
- lib/kaal/delayed_job/mysql_version_support.rb
|
|
118
|
+
- lib/kaal/delayed_job/redis_engine.rb
|
|
119
|
+
- lib/kaal/delayed_job/registry.rb
|
|
120
|
+
- lib/kaal/dispatch/database_engine.rb
|
|
108
121
|
- lib/kaal/dispatch/memory_engine.rb
|
|
109
122
|
- lib/kaal/dispatch/redis_engine.rb
|
|
110
123
|
- lib/kaal/dispatch/registry.rb
|
|
124
|
+
- lib/kaal/internal/active_record.rb
|
|
125
|
+
- lib/kaal/internal/active_record/base_record.rb
|
|
126
|
+
- lib/kaal/internal/active_record/connection_support.rb
|
|
127
|
+
- lib/kaal/internal/active_record/database_backend.rb
|
|
128
|
+
- lib/kaal/internal/active_record/definition_record.rb
|
|
129
|
+
- lib/kaal/internal/active_record/definition_registry.rb
|
|
130
|
+
- lib/kaal/internal/active_record/delayed_job_record.rb
|
|
131
|
+
- lib/kaal/internal/active_record/delayed_job_registry.rb
|
|
132
|
+
- lib/kaal/internal/active_record/dispatch_record.rb
|
|
133
|
+
- lib/kaal/internal/active_record/dispatch_registry.rb
|
|
134
|
+
- lib/kaal/internal/active_record/lock_record.rb
|
|
135
|
+
- lib/kaal/internal/active_record/migration_templates.rb
|
|
136
|
+
- lib/kaal/internal/active_record/mysql_backend.rb
|
|
137
|
+
- lib/kaal/internal/active_record/postgres_backend.rb
|
|
138
|
+
- lib/kaal/internal/sequel.rb
|
|
139
|
+
- lib/kaal/internal/sequel/database_backend.rb
|
|
140
|
+
- lib/kaal/internal/sequel/mysql_backend.rb
|
|
141
|
+
- lib/kaal/internal/sequel/postgres_backend.rb
|
|
142
|
+
- lib/kaal/job_dispatcher.rb
|
|
143
|
+
- lib/kaal/persistence/database.rb
|
|
144
|
+
- lib/kaal/persistence/migration_templates.rb
|
|
111
145
|
- lib/kaal/register_conflict_support.rb
|
|
112
146
|
- lib/kaal/registry.rb
|
|
113
147
|
- lib/kaal/runtime.rb
|
|
@@ -123,6 +157,7 @@ files:
|
|
|
123
157
|
- lib/kaal/scheduler_file/loader.rb
|
|
124
158
|
- lib/kaal/scheduler_file/payload_loader.rb
|
|
125
159
|
- lib/kaal/scheduler_file/placeholder_support.rb
|
|
160
|
+
- lib/kaal/sequel_support.rb
|
|
126
161
|
- lib/kaal/support/hash_tools.rb
|
|
127
162
|
- lib/kaal/utils.rb
|
|
128
163
|
- lib/kaal/utils/cron_humanizer.rb
|