kaal 0.5.0 → 0.6.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 +24 -24
- data/config/kaal.yml +12 -0
- data/lib/kaal/backend/adapter.rb +4 -0
- data/lib/kaal/cli.rb +38 -34
- data/lib/kaal/config/backend_factory.rb +178 -0
- data/lib/kaal/config/configuration.rb +65 -7
- data/lib/kaal/config/file_loader.rb +187 -0
- data/lib/kaal/config.rb +2 -0
- data/lib/kaal/runtime/scheduler_boot_loader.rb +1 -1
- data/lib/kaal/scheduler_file/loader.rb +1 -1
- data/lib/kaal/version.rb +1 -1
- data/lib/kaal.rb +7 -0
- data/sig/00_types.rbs +12 -0
- data/sig/dependencies.rbs +49 -0
- data/sig/kaal/active_record_support.rbs +23 -0
- data/sig/kaal/backend/adapter.rbs +26 -0
- data/sig/kaal/backend/dispatch_attempt_logger.rbs +17 -0
- data/sig/kaal/backend/dispatch_logging.rbs +23 -0
- data/sig/kaal/backend/dispatch_registry_accessor.rbs +17 -0
- data/sig/kaal/backend/memory_adapter.rbs +33 -0
- data/sig/kaal/backend/mysql.rbs +25 -0
- data/sig/kaal/backend/postgres.rbs +19 -0
- data/sig/kaal/backend/redis_adapter.rbs +41 -0
- data/sig/kaal/backend/sqlite.rbs +19 -0
- data/sig/kaal/cli.rbs +41 -0
- data/sig/kaal/config/backend_factory.rbs +41 -0
- data/sig/kaal/config/configuration.rbs +70 -0
- data/sig/kaal/config/delayed_job_security_policy.rbs +19 -0
- data/sig/kaal/config/file_loader.rbs +35 -0
- data/sig/kaal/config/scheduler_config_error.rbs +4 -0
- data/sig/kaal/config/scheduler_time_zone_resolver.rbs +19 -0
- data/sig/kaal/config.rbs +11 -0
- data/sig/kaal/core/coordinator.rbs +103 -0
- data/sig/kaal/core/enabled_entry_enumerator.rbs +21 -0
- data/sig/kaal/core/occurrence_finder.rbs +9 -0
- data/sig/kaal/core.rbs +9 -0
- data/sig/kaal/definition/database_engine.rbs +25 -0
- data/sig/kaal/definition/memory_engine.rbs +23 -0
- data/sig/kaal/definition/persistence_helpers.rbs +9 -0
- data/sig/kaal/definition/redis_engine.rbs +33 -0
- data/sig/kaal/definition/registry.rbs +29 -0
- data/sig/kaal/definitions/registration_service.rbs +27 -0
- data/sig/kaal/definitions/registry_accessor.rbs +17 -0
- data/sig/kaal/delayed_job/database_engine.rbs +37 -0
- data/sig/kaal/delayed_job/dispatch_failure_logger.rbs +7 -0
- data/sig/kaal/delayed_job/memory_engine.rbs +29 -0
- data/sig/kaal/delayed_job/mysql_version_support.rbs +15 -0
- data/sig/kaal/delayed_job/redis_engine.rbs +31 -0
- data/sig/kaal/delayed_job/registry.rbs +20 -0
- data/sig/kaal/dispatch/database_engine.rbs +39 -0
- data/sig/kaal/dispatch/memory_engine.rbs +23 -0
- data/sig/kaal/dispatch/redis_engine.rbs +25 -0
- data/sig/kaal/dispatch/registry.rbs +11 -0
- data/sig/kaal/internal/active_record/base_record.rbs +8 -0
- data/sig/kaal/internal/active_record/connection_support.rbs +25 -0
- data/sig/kaal/internal/active_record/database_backend.rbs +37 -0
- data/sig/kaal/internal/active_record/definition_record.rbs +8 -0
- data/sig/kaal/internal/active_record/definition_registry.rbs +27 -0
- data/sig/kaal/internal/active_record/delayed_job_record.rbs +8 -0
- data/sig/kaal/internal/active_record/delayed_job_registry.rbs +39 -0
- data/sig/kaal/internal/active_record/dispatch_record.rbs +8 -0
- data/sig/kaal/internal/active_record/dispatch_registry.rbs +43 -0
- data/sig/kaal/internal/active_record/lock_record.rbs +8 -0
- data/sig/kaal/internal/active_record/migration_templates.rbs +17 -0
- data/sig/kaal/internal/active_record/mysql_backend.rbs +45 -0
- data/sig/kaal/internal/active_record/postgres_backend.rbs +41 -0
- data/sig/kaal/internal/active_record.rbs +0 -0
- data/sig/kaal/internal/sequel/database_backend.rbs +39 -0
- data/sig/kaal/internal/sequel/mysql_backend.rbs +47 -0
- data/sig/kaal/internal/sequel/postgres_backend.rbs +43 -0
- data/sig/kaal/internal/sequel.rbs +0 -0
- data/sig/kaal/job_dispatcher.rbs +19 -0
- data/sig/kaal/persistence/database.rbs +19 -0
- data/sig/kaal/persistence/migration_templates.rbs +15 -0
- data/sig/kaal/register_conflict_support.rbs +11 -0
- data/sig/kaal/registry.rbs +44 -0
- data/sig/kaal/runtime/runtime_context.rbs +23 -0
- data/sig/kaal/runtime/scheduler_boot_loader.rbs +23 -0
- data/sig/kaal/runtime/signal_handler_chain.rbs +19 -0
- data/sig/kaal/runtime/signal_handler_installer.rbs +19 -0
- data/sig/kaal/runtime.rbs +11 -0
- data/sig/kaal/scheduler_file/hash_transform.rbs +9 -0
- data/sig/kaal/scheduler_file/helper_bundle.rbs +15 -0
- data/sig/kaal/scheduler_file/job_applier.rbs +43 -0
- data/sig/kaal/scheduler_file/job_normalizer.rbs +27 -0
- data/sig/kaal/scheduler_file/loader.rbs +69 -0
- data/sig/kaal/scheduler_file/payload_loader.rbs +33 -0
- data/sig/kaal/scheduler_file/placeholder_support.rbs +19 -0
- data/sig/kaal/scheduler_file.rbs +9 -0
- data/sig/kaal/sequel_support.rbs +25 -0
- data/sig/kaal/support/hash_tools.rbs +27 -0
- data/sig/kaal/utils/cron_humanizer.rbs +39 -0
- data/sig/kaal/utils/cron_utils.rbs +43 -0
- data/sig/kaal/utils/idempotency_key_generator.rbs +5 -0
- data/sig/kaal/utils.rbs +9 -0
- data/sig/kaal/version.rbs +3 -0
- data/sig/kaal.rbs +145 -0
- metadata +90 -3
- data/config/kaal.rb +0 -15
- /data/config/{scheduler.yml → kaal-scheduler.yml} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0d8c12714ca483db0abe733287ae543ecd206e58c02b228983aa0fb506671542
|
|
4
|
+
data.tar.gz: 3236ad6f7721d80424a3b725542c66f0633a3a21ed42d52514a5294b75013461
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a7213b5670154c87e4115761d62ee9e5955bd84e520ac3d3dc44dc5118c7840aeb6b6d82ad7f71aa8fe1b7fb32430abd59f636c2d14a0450054af6de7c695105
|
|
7
|
+
data.tar.gz: 790385b5f77017e8001e2c9c3e38484acdab8e733dc5cd15d1bf0a39c6c2074fa9756c7226328446bc69b9044895b0644bdb521725b6992780265d5d0a296fb0
|
data/README.md
CHANGED
|
@@ -21,43 +21,43 @@ bundle exec kaal init --backend=memory
|
|
|
21
21
|
|
|
22
22
|
`kaal init` creates:
|
|
23
23
|
|
|
24
|
-
- `config/kaal.
|
|
25
|
-
- `config/scheduler.yml`
|
|
24
|
+
- `config/kaal.yml`
|
|
25
|
+
- `config/kaal-scheduler.yml`
|
|
26
26
|
|
|
27
27
|
Supported backends:
|
|
28
28
|
|
|
29
29
|
- `memory`
|
|
30
30
|
- `redis`
|
|
31
31
|
|
|
32
|
-
If you want SQL persistence instead, add the runtime libraries your app uses, such as `sequel`, `activerecord`, `sqlite3`, `pg`, or `mysql2`, then
|
|
32
|
+
If you want SQL persistence instead, add the runtime libraries your app uses, such as `sequel`, `activerecord`, `sqlite3`, `pg`, or `mysql2`, then set `backend: sqlite/postgres/mysql` plus `backend_config` in `config/kaal.yml`.
|
|
33
33
|
|
|
34
34
|
## Configuration
|
|
35
35
|
|
|
36
|
-
Generated `config/kaal.
|
|
36
|
+
Generated `config/kaal.yml` is the primary entrypoint:
|
|
37
37
|
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
38
|
+
```yaml
|
|
39
|
+
defaults:
|
|
40
|
+
backend: memory
|
|
41
|
+
namespace: kaal
|
|
42
|
+
tick_interval: 5
|
|
43
|
+
window_lookback: 120
|
|
44
|
+
window_lookahead: 0
|
|
45
|
+
lease_ttl: 125
|
|
46
|
+
scheduler_config_path: config/kaal-scheduler.yml
|
|
47
|
+
enable_dispatch_recovery: true
|
|
48
|
+
enable_log_dispatch_registry: false
|
|
49
|
+
delayed_job_allowed_class_prefixes: []
|
|
50
|
+
backend_config: {}
|
|
48
51
|
```
|
|
49
52
|
|
|
50
53
|
Redis path:
|
|
51
54
|
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
config.backend = Kaal::Backend::RedisAdapter.new(redis)
|
|
59
|
-
config.scheduler_config_path = 'config/scheduler.yml'
|
|
60
|
-
end
|
|
55
|
+
```yaml
|
|
56
|
+
defaults:
|
|
57
|
+
backend: redis
|
|
58
|
+
scheduler_config_path: config/kaal-scheduler.yml
|
|
59
|
+
backend_config:
|
|
60
|
+
url: redis://127.0.0.1:6379/0
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
Time zone behavior is explicit:
|
|
@@ -67,7 +67,7 @@ Time zone behavior is explicit:
|
|
|
67
67
|
|
|
68
68
|
## Scheduler File
|
|
69
69
|
|
|
70
|
-
Default scheduler definitions live at `config/scheduler.yml`:
|
|
70
|
+
Default scheduler definitions live at `config/kaal-scheduler.yml`:
|
|
71
71
|
|
|
72
72
|
```yaml
|
|
73
73
|
defaults:
|
data/config/kaal.yml
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
defaults:
|
|
2
|
+
backend: memory
|
|
3
|
+
namespace: kaal
|
|
4
|
+
tick_interval: 5
|
|
5
|
+
window_lookback: 120
|
|
6
|
+
window_lookahead: 0
|
|
7
|
+
lease_ttl: 125
|
|
8
|
+
scheduler_config_path: config/kaal-scheduler.yml
|
|
9
|
+
enable_dispatch_recovery: true
|
|
10
|
+
enable_log_dispatch_registry: false
|
|
11
|
+
delayed_job_allowed_class_prefixes: []
|
|
12
|
+
backend_config: {}
|
data/lib/kaal/backend/adapter.rb
CHANGED
data/lib/kaal/cli.rb
CHANGED
|
@@ -19,10 +19,10 @@ module Kaal
|
|
|
19
19
|
def load_project!
|
|
20
20
|
Kaal.reset_configuration!
|
|
21
21
|
Kaal.reset_registry!
|
|
22
|
-
load config_path
|
|
23
|
-
Kaal.warn_on_risky_configuration!
|
|
24
22
|
runtime_context = RuntimeContext.default(root_path: root_path)
|
|
25
|
-
Kaal.
|
|
23
|
+
Kaal.load_config_file!(path: config_path, runtime_context:)
|
|
24
|
+
Kaal.warn_on_risky_configuration!
|
|
25
|
+
Kaal.load_scheduler_file!(runtime_context: runtime_context)
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
def root_path
|
|
@@ -33,42 +33,46 @@ module Kaal
|
|
|
33
33
|
config = options[:config]
|
|
34
34
|
return File.expand_path(config) if config
|
|
35
35
|
|
|
36
|
-
File.join(root_path, 'config', 'kaal.
|
|
36
|
+
File.join(root_path, 'config', 'kaal.yml')
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
def scheduler_path
|
|
40
|
-
File.join(root_path, 'config', 'scheduler.yml')
|
|
40
|
+
File.join(root_path, 'config', 'kaal-scheduler.yml')
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
def render_config_template(backend)
|
|
44
44
|
case backend
|
|
45
45
|
when 'memory'
|
|
46
|
-
<<~
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
46
|
+
<<~YAML
|
|
47
|
+
defaults:
|
|
48
|
+
backend: memory
|
|
49
|
+
namespace: kaal
|
|
50
|
+
tick_interval: 5
|
|
51
|
+
window_lookback: 120
|
|
52
|
+
window_lookahead: 0
|
|
53
|
+
lease_ttl: 125
|
|
54
|
+
scheduler_config_path: config/kaal-scheduler.yml
|
|
55
|
+
enable_dispatch_recovery: true
|
|
56
|
+
enable_log_dispatch_registry: false
|
|
57
|
+
delayed_job_allowed_class_prefixes: []
|
|
58
|
+
backend_config: {}
|
|
59
|
+
YAML
|
|
57
60
|
when 'redis'
|
|
58
|
-
<<~
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
config.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
61
|
+
<<~YAML
|
|
62
|
+
defaults:
|
|
63
|
+
backend: redis
|
|
64
|
+
namespace: kaal
|
|
65
|
+
tick_interval: 5
|
|
66
|
+
window_lookback: 120
|
|
67
|
+
window_lookahead: 0
|
|
68
|
+
lease_ttl: 125
|
|
69
|
+
scheduler_config_path: config/kaal-scheduler.yml
|
|
70
|
+
enable_dispatch_recovery: true
|
|
71
|
+
enable_log_dispatch_registry: false
|
|
72
|
+
delayed_job_allowed_class_prefixes: []
|
|
73
|
+
backend_config:
|
|
74
|
+
url: redis://127.0.0.1:6379/0
|
|
75
|
+
YAML
|
|
72
76
|
else
|
|
73
77
|
raise Thor::Error, "Unsupported backend '#{backend}'"
|
|
74
78
|
end
|
|
@@ -95,9 +99,9 @@ module Kaal
|
|
|
95
99
|
package_name 'kaal'
|
|
96
100
|
|
|
97
101
|
class_option :root, type: :string, default: Dir.pwd, desc: 'Project root'
|
|
98
|
-
class_option :config, type: :string, desc: 'Path to config/kaal.
|
|
102
|
+
class_option :config, type: :string, desc: 'Path to config/kaal.yml'
|
|
99
103
|
|
|
100
|
-
desc 'init', 'Generate config/kaal.
|
|
104
|
+
desc 'init', 'Generate config/kaal.yml and config/kaal-scheduler.yml'
|
|
101
105
|
option :backend, type: :string, default: 'memory', enum: %w[memory redis]
|
|
102
106
|
def init
|
|
103
107
|
root = File.expand_path(options[:root])
|
|
@@ -105,8 +109,8 @@ module Kaal
|
|
|
105
109
|
writer = self.class
|
|
106
110
|
FileUtils.mkdir_p(File.join(root, 'config'))
|
|
107
111
|
|
|
108
|
-
writer.write_file(File.join(root, 'config', 'kaal.
|
|
109
|
-
writer.write_file(File.join(root, 'config', 'scheduler.yml'), scheduler_template)
|
|
112
|
+
writer.write_file(File.join(root, 'config', 'kaal.yml'), render_config_template(backend))
|
|
113
|
+
writer.write_file(File.join(root, 'config', 'kaal-scheduler.yml'), scheduler_template)
|
|
110
114
|
|
|
111
115
|
say("Initialized Kaal project for #{backend} backend")
|
|
112
116
|
end
|
|
@@ -0,0 +1,178 @@
|
|
|
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
|
+
require 'pathname'
|
|
9
|
+
require 'uri'
|
|
10
|
+
|
|
11
|
+
module Kaal
|
|
12
|
+
module Config
|
|
13
|
+
# Builds backend adapter instances from symbolic runtime configuration.
|
|
14
|
+
module BackendFactory
|
|
15
|
+
module_function
|
|
16
|
+
|
|
17
|
+
SUPPORTED_BACKENDS = %w[memory redis sqlite postgres mysql].freeze
|
|
18
|
+
|
|
19
|
+
def normalize_name(name)
|
|
20
|
+
normalized = name.to_s.strip.downcase
|
|
21
|
+
return nil if normalized.empty?
|
|
22
|
+
|
|
23
|
+
normalized = 'postgres' if normalized == 'postgresql'
|
|
24
|
+
normalized = 'mysql' if normalized == 'trilogy'
|
|
25
|
+
return normalized if SUPPORTED_BACKENDS.include?(normalized)
|
|
26
|
+
|
|
27
|
+
raise Kaal::ConfigurationError, "Unsupported backend #{name.inspect}; use memory, redis, sqlite, postgres, or mysql"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def build(name, backend_config:, namespace:, runtime_context: nil)
|
|
31
|
+
backend_name = normalize_name(name)
|
|
32
|
+
config = normalize_backend_config(backend_config)
|
|
33
|
+
|
|
34
|
+
case backend_name
|
|
35
|
+
when 'memory'
|
|
36
|
+
Kaal::Backend::MemoryAdapter.new
|
|
37
|
+
when 'redis'
|
|
38
|
+
build_redis_backend(config, namespace)
|
|
39
|
+
when 'sqlite'
|
|
40
|
+
build_sqlite_backend(config, namespace, runtime_context)
|
|
41
|
+
when 'postgres'
|
|
42
|
+
build_postgres_backend(config, namespace)
|
|
43
|
+
when 'mysql'
|
|
44
|
+
build_mysql_backend(config, namespace)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def normalize_backend_config(backend_config)
|
|
49
|
+
hash = backend_config.is_a?(Hash) ? backend_config : {}
|
|
50
|
+
Kaal::Support::HashTools.symbolize_keys(Kaal::Support::HashTools.deep_dup(hash))
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def build_redis_backend(config, namespace)
|
|
54
|
+
require_redis!
|
|
55
|
+
|
|
56
|
+
url = string_value(config[:url])
|
|
57
|
+
raise Kaal::ConfigurationError, 'redis backend requires backend_config.url or KAAL_BACKEND_URL' if url.empty?
|
|
58
|
+
|
|
59
|
+
Kaal::Backend::RedisAdapter.new(::Redis.new(url: url), namespace:)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def build_sqlite_backend(config, namespace, runtime_context)
|
|
63
|
+
return Kaal::Backend::SQLite.new(connection: build_sqlite_connection(config[:connection], runtime_context), namespace:) if config.key?(:connection)
|
|
64
|
+
|
|
65
|
+
url = string_value(config[:url])
|
|
66
|
+
database = string_value(config[:database])
|
|
67
|
+
target = url.empty? ? database : url
|
|
68
|
+
raise Kaal::ConfigurationError, 'sqlite backend requires backend_config.url, backend_config.database, or KAAL_BACKEND_URL' if target.empty?
|
|
69
|
+
|
|
70
|
+
require_sequel!
|
|
71
|
+
Kaal::Backend::SQLite.new(
|
|
72
|
+
database: sequel_sqlite_database(target, runtime_context),
|
|
73
|
+
namespace:
|
|
74
|
+
)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def build_postgres_backend(config, namespace)
|
|
78
|
+
if config.key?(:connection)
|
|
79
|
+
return Kaal::Backend::Postgres.new(connection: normalize_connection_hash(config[:connection], 'postgresql', nil),
|
|
80
|
+
namespace:)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
url = string_value(config[:url])
|
|
84
|
+
raise Kaal::ConfigurationError, 'postgres backend requires backend_config.url or KAAL_BACKEND_URL' if url.empty?
|
|
85
|
+
|
|
86
|
+
require_sequel!
|
|
87
|
+
Kaal::Backend::Postgres.new(database: ::Sequel.connect(url), namespace:)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def build_mysql_backend(config, namespace)
|
|
91
|
+
use_skip_locked = config[:use_skip_locked]
|
|
92
|
+
skip_locked_configured = config.key?(:use_skip_locked)
|
|
93
|
+
|
|
94
|
+
if config.key?(:connection)
|
|
95
|
+
connection = normalize_connection_hash(config[:connection], 'mysql2', nil)
|
|
96
|
+
return Kaal::Backend::MySQL.new(connection:, namespace:) unless skip_locked_configured
|
|
97
|
+
|
|
98
|
+
return Kaal::Backend::MySQL.new(connection:, namespace:, use_skip_locked:)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
url = string_value(config[:url])
|
|
102
|
+
raise Kaal::ConfigurationError, 'mysql backend requires backend_config.url or KAAL_BACKEND_URL' if url.empty?
|
|
103
|
+
|
|
104
|
+
require_sequel!
|
|
105
|
+
database = ::Sequel.connect(url)
|
|
106
|
+
return Kaal::Backend::MySQL.new(database:, namespace:) unless skip_locked_configured
|
|
107
|
+
|
|
108
|
+
Kaal::Backend::MySQL.new(database:, namespace:, use_skip_locked:)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def build_sqlite_connection(connection, runtime_context)
|
|
112
|
+
normalize_connection_hash(connection, 'sqlite3', runtime_context)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def normalize_connection_hash(connection, default_adapter, runtime_context)
|
|
116
|
+
case connection
|
|
117
|
+
when String
|
|
118
|
+
connection
|
|
119
|
+
when Hash
|
|
120
|
+
normalized = Kaal::Support::HashTools.symbolize_keys(Kaal::Support::HashTools.deep_dup(connection))
|
|
121
|
+
adapter = string_value(normalized[:adapter])
|
|
122
|
+
normalized_adapter = adapter.empty? ? default_adapter : adapter
|
|
123
|
+
normalized[:adapter] = normalized_adapter
|
|
124
|
+
normalized[:database] = resolve_sqlite_database_path(normalized[:database], runtime_context) if normalized_adapter == 'sqlite3'
|
|
125
|
+
normalized
|
|
126
|
+
else
|
|
127
|
+
raise Kaal::ConfigurationError, 'backend_config.connection must be a URL string or hash'
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def resolve_sqlite_database_path(database, runtime_context)
|
|
132
|
+
value = string_value(database)
|
|
133
|
+
return value if value.empty?
|
|
134
|
+
return value if sqlite_uri?(value)
|
|
135
|
+
return ensure_sqlite_directory!(value) if Pathname.new(value).absolute?
|
|
136
|
+
|
|
137
|
+
resolved = runtime_context ? runtime_context.resolve_path(value) : value
|
|
138
|
+
ensure_sqlite_directory!(resolved)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def sqlite_uri?(value)
|
|
142
|
+
value.start_with?('sqlite:', 'file:')
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def sequel_sqlite_database(target, runtime_context)
|
|
146
|
+
return ::Sequel.connect(target) if sqlite_uri?(target)
|
|
147
|
+
|
|
148
|
+
::Sequel.connect(adapter: 'sqlite', database: resolve_sqlite_database_path(target, runtime_context))
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def ensure_sqlite_directory!(database_path)
|
|
152
|
+
directory = File.dirname(database_path)
|
|
153
|
+
FileUtils.mkdir_p(directory) unless directory == '.' || directory.empty?
|
|
154
|
+
database_path
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def adapter_name_for_error(adapter)
|
|
158
|
+
adapter == 'postgresql' ? 'postgres' : 'mysql'
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def string_value(value)
|
|
162
|
+
value.to_s.strip
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def require_redis!
|
|
166
|
+
require 'redis'
|
|
167
|
+
rescue LoadError => e
|
|
168
|
+
raise LoadError, "#{e.message}. Add `gem 'redis'` to your Gemfile to use the Redis-backed Kaal adapter.", cause: e
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def require_sequel!
|
|
172
|
+
require 'sequel'
|
|
173
|
+
rescue LoadError => e
|
|
174
|
+
raise LoadError, "#{e.message}. Add `gem 'sequel'` to your Gemfile to use Sequel-backed Kaal SQL support.", cause: e
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
@@ -12,7 +12,8 @@ module Kaal
|
|
|
12
12
|
# @example Basic configuration
|
|
13
13
|
# Kaal.configure do |config|
|
|
14
14
|
# config.tick_interval = 5
|
|
15
|
-
# config.
|
|
15
|
+
# config.backend_config = { url: ENV['KAAL_BACKEND_URL'] }
|
|
16
|
+
# config.backend = :redis
|
|
16
17
|
# end
|
|
17
18
|
class Configuration
|
|
18
19
|
# Default values for all configuration options
|
|
@@ -23,13 +24,14 @@ module Kaal
|
|
|
23
24
|
lease_ttl: 125, # Must be >= window_lookback + tick_interval (120 + 5 = 125)
|
|
24
25
|
namespace: 'kaal',
|
|
25
26
|
backend: nil,
|
|
27
|
+
backend_config: {},
|
|
26
28
|
logger: nil,
|
|
27
29
|
time_zone: nil,
|
|
28
30
|
enable_log_dispatch_registry: false,
|
|
29
31
|
enable_dispatch_recovery: true,
|
|
30
32
|
recovery_window: 86_400, # 24 hours in seconds
|
|
31
33
|
recovery_startup_jitter: 5, # max random delay in seconds
|
|
32
|
-
scheduler_config_path: 'config/scheduler.yml',
|
|
34
|
+
scheduler_config_path: 'config/kaal-scheduler.yml',
|
|
33
35
|
scheduler_conflict_policy: :error,
|
|
34
36
|
scheduler_missing_file_policy: :warn,
|
|
35
37
|
delayed_job_allowed_class_prefixes: []
|
|
@@ -41,6 +43,8 @@ module Kaal
|
|
|
41
43
|
# @return [Configuration] a new instance with all defaults set
|
|
42
44
|
def initialize
|
|
43
45
|
@values = DEFAULTS.dup
|
|
46
|
+
@backend_name = nil
|
|
47
|
+
@backend_runtime_context = nil
|
|
44
48
|
end
|
|
45
49
|
|
|
46
50
|
##
|
|
@@ -111,6 +115,7 @@ module Kaal
|
|
|
111
115
|
lease_ttl: @values[:lease_ttl],
|
|
112
116
|
namespace: @values[:namespace],
|
|
113
117
|
backend: backend&.class&.name,
|
|
118
|
+
backend_config: Kaal::Support::HashTools.deep_dup(@values[:backend_config]),
|
|
114
119
|
logger: logger&.class&.name,
|
|
115
120
|
time_zone: @values[:time_zone],
|
|
116
121
|
enable_log_dispatch_registry: @values[:enable_log_dispatch_registry],
|
|
@@ -133,6 +138,7 @@ module Kaal
|
|
|
133
138
|
add_window_lookahead_error(errors)
|
|
134
139
|
add_lease_ttl_error(errors)
|
|
135
140
|
add_namespace_error(errors)
|
|
141
|
+
add_backend_config_error(errors)
|
|
136
142
|
add_lease_ttl_window_error(errors)
|
|
137
143
|
add_scheduler_config_path_error(errors)
|
|
138
144
|
add_scheduler_conflict_policy_error(errors)
|
|
@@ -174,6 +180,12 @@ module Kaal
|
|
|
174
180
|
errors << 'namespace cannot be blank'
|
|
175
181
|
end
|
|
176
182
|
|
|
183
|
+
def add_backend_config_error(errors)
|
|
184
|
+
return if @values[:backend_config].is_a?(Hash)
|
|
185
|
+
|
|
186
|
+
errors << 'backend_config must be a hash'
|
|
187
|
+
end
|
|
188
|
+
|
|
177
189
|
def add_lease_ttl_window_error(errors)
|
|
178
190
|
lease_ttl = @values[:lease_ttl].to_i
|
|
179
191
|
window_lookback = @values[:window_lookback].to_i
|
|
@@ -224,22 +236,25 @@ module Kaal
|
|
|
224
236
|
|
|
225
237
|
def set_value(key, value)
|
|
226
238
|
@values[key] = normalize_value(key, value)
|
|
239
|
+
rebuild_symbolic_backend_if_needed(key)
|
|
227
240
|
end
|
|
228
241
|
|
|
229
242
|
def normalize_value(key, value)
|
|
230
|
-
return value unless @values.key?(key)
|
|
231
|
-
|
|
232
243
|
case key
|
|
244
|
+
when :backend
|
|
245
|
+
normalize_backend(value)
|
|
246
|
+
when :backend_config
|
|
247
|
+
value.is_a?(Hash) ? Kaal::Support::HashTools.symbolize_keys(Kaal::Support::HashTools.deep_dup(value)) : (value || {})
|
|
233
248
|
when :tick_interval, :window_lookback, :window_lookahead, :lease_ttl
|
|
234
249
|
value.to_i
|
|
235
250
|
when :namespace, :scheduler_config_path
|
|
236
251
|
value.to_s
|
|
237
252
|
when :time_zone
|
|
238
|
-
value
|
|
253
|
+
normalize_optional_string(value)
|
|
239
254
|
when :enable_log_dispatch_registry
|
|
240
|
-
value
|
|
255
|
+
!!value
|
|
241
256
|
when :scheduler_conflict_policy, :scheduler_missing_file_policy
|
|
242
|
-
value
|
|
257
|
+
normalize_optional_symbol(value)
|
|
243
258
|
when :delayed_job_allowed_class_prefixes
|
|
244
259
|
normalize_delayed_job_allowed_class_prefixes(value)
|
|
245
260
|
else
|
|
@@ -247,12 +262,55 @@ module Kaal
|
|
|
247
262
|
end
|
|
248
263
|
end
|
|
249
264
|
|
|
265
|
+
def normalize_backend(value)
|
|
266
|
+
unless value.is_a?(String) || value.is_a?(Symbol)
|
|
267
|
+
@backend_name = nil
|
|
268
|
+
return value
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
normalized_backend_name = Kaal::Config::BackendFactory.normalize_name(value)
|
|
272
|
+
backend = Kaal::Config::BackendFactory.build(
|
|
273
|
+
normalized_backend_name,
|
|
274
|
+
backend_config: @values[:backend_config],
|
|
275
|
+
namespace: @values[:namespace],
|
|
276
|
+
runtime_context: @backend_runtime_context
|
|
277
|
+
)
|
|
278
|
+
@backend_name = normalized_backend_name
|
|
279
|
+
backend
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def apply_backend_runtime_context(runtime_context)
|
|
283
|
+
@backend_runtime_context = runtime_context
|
|
284
|
+
end
|
|
285
|
+
public :apply_backend_runtime_context
|
|
286
|
+
|
|
287
|
+
def rebuild_symbolic_backend_if_needed(key)
|
|
288
|
+
return unless @backend_name
|
|
289
|
+
return unless %i[backend_config namespace backend].include?(key)
|
|
290
|
+
return if key == :backend
|
|
291
|
+
|
|
292
|
+
@values[:backend] = Kaal::Config::BackendFactory.build(
|
|
293
|
+
@backend_name,
|
|
294
|
+
backend_config: @values[:backend_config],
|
|
295
|
+
namespace: @values[:namespace],
|
|
296
|
+
runtime_context: @backend_runtime_context
|
|
297
|
+
)
|
|
298
|
+
end
|
|
299
|
+
|
|
250
300
|
def normalize_delayed_job_allowed_class_prefixes(value)
|
|
251
301
|
Array(value).filter_map do |entry|
|
|
252
302
|
normalized_entry = entry.to_s.strip
|
|
253
303
|
normalized_entry unless normalized_entry.empty?
|
|
254
304
|
end
|
|
255
305
|
end
|
|
306
|
+
|
|
307
|
+
def normalize_optional_string(value)
|
|
308
|
+
value&.to_s
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
def normalize_optional_symbol(value)
|
|
312
|
+
value&.to_sym
|
|
313
|
+
end
|
|
256
314
|
end
|
|
257
315
|
|
|
258
316
|
##
|