activejob-temporal 0.4.0 → 0.5.1
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/CHANGELOG.md +26 -0
- data/CONTRIBUTING.md +7 -7
- data/README.md +5 -5
- data/activejob-temporal.gemspec +2 -2
- data/bin/temporal-worker +3 -3
- data/gemfiles/temporalio_contract.gemfile +2 -0
- data/lib/activejob/temporal/activities/aj_runner_activity.rb +1 -2
- data/lib/activejob/temporal/client.rb +34 -0
- data/lib/activejob/temporal/configuration.rb +34 -51
- data/lib/activejob/temporal/credential_refresher.rb +23 -12
- data/lib/activejob/temporal/dead_letter_queue.rb +1 -2
- data/lib/activejob/temporal/job_payload_builder.rb +1 -2
- data/lib/activejob/temporal/locales/en.yml +4 -6
- data/lib/activejob/temporal/observability/datadog.rb +1 -2
- data/lib/activejob/temporal/observability/prometheus.rb +1 -2
- data/lib/activejob/temporal/retry_handler_extractor.rb +1 -2
- data/lib/activejob/temporal/temporal_options.rb +1 -2
- data/lib/activejob/temporal/version.rb +1 -1
- data/lib/activejob/temporal/worker_pool.rb +1 -2
- data/lib/activejob/temporal/workflow_enqueuer.rb +1 -2
- metadata +6 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f88f38d49d2e111cfcbdfe5bc2f45fb4ab9f202478e8e248dda74bce56925205
|
|
4
|
+
data.tar.gz: a560b2d0e446dd867915298e75faabe60eb2c1f07bd0592cf7b3be4011ad07d9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 885994ed9a18b4b071736502f73e9cd379a212a23739eea1a1d3308b2634261f273b82070aa154504f99a757b30ba2135b05696253816dbac2a67ea02334403a
|
|
7
|
+
data.tar.gz: '092927525f27f3ce13f07608f098dd53b87c2daf2665d98d3d6fc11ad4f7e243cd9701edf7dfa6a14130a89097ed04408706932ab5c59f5484803fb399b477e5'
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.5.1] - 2026-11-11
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- Allow temporalio 1.7 through 1.11 (dependency constraint is now `>= 1.4.0, < 1.12`); 1.10.1 and 1.11.0 added to the SDK contract-test matrix. Note for consumers upgrading within the range: since temporalio 1.7, workers check payload sizes before sending and fail an oversized task completion retryably instead of letting the server fail it.
|
|
14
|
+
- Ruby baseline moves from 4.0.3 to 4.0.9 (`.ruby-version`, CI, tools, docs and the example app). `ubuntu-latest` is now Ubuntu 26.04, where `setup-ruby` has no Ruby 4.0.3 build.
|
|
15
|
+
|
|
16
|
+
## [0.5.0] - 2026-08-07
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
- Configuration now fails to validate when `api_key` or `api_key_file` is set while `tls` is left unset. The Temporal SDK enables TLS on its own whenever an API key is present, so leaving `tls` at `nil` silently coupled transport security to an unrelated setting and failed the handshake against a plaintext frontend.
|
|
20
|
+
- The client logs `credential_source_shadowed` when two sources for the same credential are configured (`api_key` alongside `api_key_file`, or `tls` alongside the `tls_*_path` settings). Precedence was already defined but silent.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
- **Breaking:** `tls_cert_watch` and `api_key_watch` are replaced by a single `credential_watch`, default `true`. A file path is only configured because the credential behind it rotates, so watching every configured credential file is now the default instead of two opt-in flags that could each be forgotten.
|
|
24
|
+
- **Breaking:** `tls_reload_signal` is renamed `reload_signal` (`ACTIVEJOB_TEMPORAL_TLS_RELOAD_SIGNAL` becomes `ACTIVEJOB_TEMPORAL_RELOAD_SIGNAL`). It rebuilds the whole client and re-resolves the API key, not just TLS material.
|
|
25
|
+
- **Breaking:** `CredentialRefresher.from_config` no longer accepts `on_api_key_change`. Applying a rotated token mutates the live connection, so it is the same call in every process and had no caller that overrode it.
|
|
26
|
+
|
|
27
|
+
### Documentation
|
|
28
|
+
- `CredentialRefresher.from_config` and the worker setup guide now state that a process running its own `Temporalio::Worker` must pass `on_tls_change`. The default `reload_client!` closes the client it replaces, which is the one such a worker is still polling on. `bin/temporal-worker` already passes it.
|
|
29
|
+
|
|
30
|
+
### Migration from 0.4.x
|
|
31
|
+
- Rename `tls_cert_watch` / `api_key_watch` to `credential_watch`, or drop them: watching is on by default and applies to whatever credential files are configured.
|
|
32
|
+
- Rename `tls_reload_signal` to `reload_signal`, and `ACTIVEJOB_TEMPORAL_TLS_RELOAD_SIGNAL` to `ACTIVEJOB_TEMPORAL_RELOAD_SIGNAL`.
|
|
33
|
+
- Set `tls` explicitly wherever `api_key` or `api_key_file` is configured: `config.tls = false` for a plaintext in-cluster frontend, `config.tls = true` for Temporal Cloud. Boot now fails until you do.
|
|
34
|
+
- Drop `on_api_key_change:` from any `CredentialRefresher.from_config` call.
|
|
35
|
+
|
|
10
36
|
## [0.4.0] - 2026-08-07
|
|
11
37
|
|
|
12
38
|
### Added
|
data/CONTRIBUTING.md
CHANGED
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
## Ruby Baseline
|
|
4
4
|
|
|
5
|
-
Use Ruby 4.0.
|
|
5
|
+
Use Ruby 4.0.9 for local development and validation. The repository targets Ruby 4+ and does not require installing Ruby 3.
|
|
6
6
|
|
|
7
7
|
See [Ruby Baseline](docs/ruby_baseline.md) for the source-of-truth files, CI coverage, and external tooling notes.
|
|
8
8
|
|
|
9
9
|
Run validation commands through the Ruby 4 toolchain:
|
|
10
10
|
|
|
11
11
|
```sh
|
|
12
|
-
rvm 4.0.
|
|
13
|
-
rvm 4.0.
|
|
14
|
-
rvm 4.0.
|
|
15
|
-
rvm 4.0.
|
|
12
|
+
rvm 4.0.9 do bundle install
|
|
13
|
+
rvm 4.0.9 do bundle exec rake spec:unit
|
|
14
|
+
rvm 4.0.9 do bundle exec rubocop
|
|
15
|
+
rvm 4.0.9 do bundle exec rake build
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
## Mutation Testing
|
|
@@ -20,7 +20,7 @@ rvm 4.0.3 do bundle exec rake build
|
|
|
20
20
|
Mutation testing runs a scoped Mutant baseline against deterministic unit-level code:
|
|
21
21
|
|
|
22
22
|
```sh
|
|
23
|
-
rvm 4.0.
|
|
23
|
+
rvm 4.0.9 do bundle exec rake mutation
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
The default subject list is intentionally small so the task stays fast and does not require a local Temporal server. Expand `.mutant.yml` as specs are hardened around additional code paths.
|
|
@@ -46,7 +46,7 @@ Do not add a README maintainability badge until the repository has been added to
|
|
|
46
46
|
Generate release changelog updates from merged GitHub pull requests and closed issues:
|
|
47
47
|
|
|
48
48
|
```sh
|
|
49
|
-
CHANGELOG_GITHUB_TOKEN=... rvm 4.0.
|
|
49
|
+
CHANGELOG_GITHUB_TOKEN=... rvm 4.0.9 do bundle exec rake changelog:generate
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
The task also accepts `GITHUB_TOKEN` when `CHANGELOG_GITHUB_TOKEN` is not set. Review the generated `CHANGELOG.md` before committing release notes.
|
data/README.md
CHANGED
|
@@ -172,16 +172,16 @@ See [examples/basic_rails_app](examples/basic_rails_app/) for a Docker Compose R
|
|
|
172
172
|
Install dependencies and run the focused local checks:
|
|
173
173
|
|
|
174
174
|
```bash
|
|
175
|
-
rvm 4.0.
|
|
176
|
-
rvm 4.0.
|
|
177
|
-
rvm 4.0.
|
|
178
|
-
rvm 4.0.
|
|
175
|
+
rvm 4.0.9 do bundle install
|
|
176
|
+
rvm 4.0.9 do bundle exec rake spec:unit
|
|
177
|
+
rvm 4.0.9 do bundle exec rubocop
|
|
178
|
+
rvm 4.0.9 do bundle exec rake build
|
|
179
179
|
```
|
|
180
180
|
|
|
181
181
|
For changes near configured mutation subjects, also run:
|
|
182
182
|
|
|
183
183
|
```bash
|
|
184
|
-
rvm 4.0.
|
|
184
|
+
rvm 4.0.9 do bundle exec rake mutation
|
|
185
185
|
```
|
|
186
186
|
|
|
187
187
|
Keep docs updated when behavior changes. The scoped mutation task runs on Ruby 4. Mutant 0.16 may warn about an older parser dependency; keep using the Ruby 4 toolchain and treat parser failures on new Ruby syntax as a mutation tooling limitation.
|
data/activejob-temporal.gemspec
CHANGED
|
@@ -37,7 +37,7 @@ Gem::Specification.new do |spec|
|
|
|
37
37
|
spec.add_dependency "activemodel", ">= 7.2", "< 9"
|
|
38
38
|
spec.add_dependency "concurrent-ruby", "~> 1.1"
|
|
39
39
|
spec.add_dependency "globalid", ">= 0.3"
|
|
40
|
-
spec.add_dependency "temporalio", ">= 1.4.0", "< 1.
|
|
40
|
+
spec.add_dependency "temporalio", ">= 1.4.0", "< 1.12"
|
|
41
41
|
|
|
42
42
|
# listen is an optional runtime dependency, required lazily only when credential_file_events is
|
|
43
43
|
# enabled. Without it credentials still rotate, just on the poll interval instead of instantly.
|
|
@@ -49,7 +49,7 @@ Gem::Specification.new do |spec|
|
|
|
49
49
|
spec.add_development_dependency "mutant-minitest", "~> 0.16"
|
|
50
50
|
spec.add_development_dependency "prometheus-client", "~> 4.2"
|
|
51
51
|
spec.add_development_dependency "rake", "~> 13.2"
|
|
52
|
-
spec.add_development_dependency "rubocop", "~> 1.
|
|
52
|
+
spec.add_development_dependency "rubocop", "~> 1.92"
|
|
53
53
|
spec.add_development_dependency "simplecov", "~> 0.22"
|
|
54
54
|
spec.add_development_dependency "simplecov-lcov", "~> 0.9"
|
|
55
55
|
spec.add_development_dependency "yard", "~> 0.9"
|
data/bin/temporal-worker
CHANGED
|
@@ -107,11 +107,11 @@ if pool_size < 1
|
|
|
107
107
|
exit(1)
|
|
108
108
|
end
|
|
109
109
|
|
|
110
|
-
reload_signal = config.
|
|
110
|
+
reload_signal = config.reload_signal.to_s.sub(/\ASIG/i, "").upcase
|
|
111
111
|
unless Signal.list.key?(reload_signal) && !ActiveJob::Temporal::UNTRAPPABLE_SIGNALS.include?(reload_signal)
|
|
112
112
|
warn(
|
|
113
|
-
"Error:
|
|
114
|
-
"got: #{config.
|
|
113
|
+
"Error: ACTIVEJOB_TEMPORAL_RELOAD_SIGNAL must be a signal name safe to trap, " \
|
|
114
|
+
"got: #{config.reload_signal.inspect}"
|
|
115
115
|
)
|
|
116
116
|
exit(1)
|
|
117
117
|
end
|
|
@@ -57,7 +57,7 @@ module ActiveJob
|
|
|
57
57
|
#
|
|
58
58
|
# @see https://docs.temporal.io/activities Temporal Activities Guide
|
|
59
59
|
# @see https://docs.temporal.io/retry-policies Temporal Retry Policies
|
|
60
|
-
# rubocop:disable Metrics/ClassLength
|
|
60
|
+
# rubocop:disable-next Metrics/ClassLength
|
|
61
61
|
class AjRunnerActivity < Temporalio::Activity::Definition
|
|
62
62
|
IDEMPOTENCY_KEY = :aj_temporal_idempotency_key
|
|
63
63
|
DESERIALIZATION_ERROR_CLASSES = [
|
|
@@ -504,7 +504,6 @@ module ActiveJob
|
|
|
504
504
|
Time.zone&.name if Time.respond_to?(:zone)
|
|
505
505
|
end
|
|
506
506
|
end
|
|
507
|
-
# rubocop:enable Metrics/ClassLength
|
|
508
507
|
end
|
|
509
508
|
end
|
|
510
509
|
end
|
|
@@ -8,6 +8,7 @@ rescue LoadError
|
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
require_relative "tls_file"
|
|
11
|
+
require_relative "logger"
|
|
11
12
|
|
|
12
13
|
module ActiveJob
|
|
13
14
|
module Temporal
|
|
@@ -121,6 +122,8 @@ module ActiveJob
|
|
|
121
122
|
def connection_kwargs(configuration)
|
|
122
123
|
kwargs = {}
|
|
123
124
|
|
|
125
|
+
warn_on_shadowed_credentials(configuration)
|
|
126
|
+
|
|
124
127
|
tls = tls_options(configuration)
|
|
125
128
|
kwargs[:tls] = tls unless tls.nil?
|
|
126
129
|
|
|
@@ -131,6 +134,37 @@ module ActiveJob
|
|
|
131
134
|
end
|
|
132
135
|
private_class_method :connection_kwargs
|
|
133
136
|
|
|
137
|
+
# Every credential has more than one possible source and the precedence between them is
|
|
138
|
+
# silent, so a config that sets two looks like it works while one of them is ignored.
|
|
139
|
+
# @api private
|
|
140
|
+
def warn_on_shadowed_credentials(configuration)
|
|
141
|
+
if credential_present?(configuration, :api_key) && credential_present?(configuration, :api_key_file)
|
|
142
|
+
Logger.warn("credential_source_shadowed", credential: "api_key", ignored: "api_key_file")
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
return unless configuration.respond_to?(:tls) && !configuration.tls.nil?
|
|
146
|
+
return if tls_path_attributes(configuration).empty?
|
|
147
|
+
|
|
148
|
+
Logger.warn(
|
|
149
|
+
"credential_source_shadowed",
|
|
150
|
+
credential: "tls",
|
|
151
|
+
ignored: tls_path_attributes(configuration).join(", ")
|
|
152
|
+
)
|
|
153
|
+
end
|
|
154
|
+
private_class_method :warn_on_shadowed_credentials
|
|
155
|
+
|
|
156
|
+
def credential_present?(configuration, attribute)
|
|
157
|
+
configuration.respond_to?(attribute) && configuration.public_send(attribute).to_s.strip != ""
|
|
158
|
+
end
|
|
159
|
+
private_class_method :credential_present?
|
|
160
|
+
|
|
161
|
+
def tls_path_attributes(configuration)
|
|
162
|
+
%i[tls_cert_path tls_key_path tls_server_root_ca_cert_path].select do |attribute|
|
|
163
|
+
credential_present?(configuration, attribute)
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
private_class_method :tls_path_attributes
|
|
167
|
+
|
|
134
168
|
# Resolves the API key: an explicit api_key wins, otherwise api_key_file is read - at
|
|
135
169
|
# connection build time, and again by {ActiveJob::Temporal.refresh_api_key!} when the
|
|
136
170
|
# token file rotates.
|
|
@@ -11,7 +11,7 @@ require_relative "payload_serializers"
|
|
|
11
11
|
require_relative "rate_limit_options"
|
|
12
12
|
require_relative "tls_file"
|
|
13
13
|
|
|
14
|
-
# rubocop:disable Metrics/ModuleLength
|
|
14
|
+
# rubocop:disable-next Metrics/ModuleLength
|
|
15
15
|
module ActiveJob
|
|
16
16
|
module Temporal
|
|
17
17
|
LOCALE_PATH = File.expand_path("locales/en.yml", __dir__)
|
|
@@ -122,18 +122,12 @@ module ActiveJob
|
|
|
122
122
|
description: "Optional TLS SNI domain override"
|
|
123
123
|
},
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
default: false,
|
|
127
|
-
env_var: "ACTIVEJOB_TEMPORAL_TLS_CERT_WATCH",
|
|
128
|
-
type: :boolean,
|
|
129
|
-
description: "Watch TLS certificate files and reload worker clients when they change"
|
|
130
|
-
},
|
|
131
|
-
|
|
132
|
-
tls_reload_signal: {
|
|
125
|
+
reload_signal: {
|
|
133
126
|
default: "HUP",
|
|
134
|
-
env_var: "
|
|
127
|
+
env_var: "ACTIVEJOB_TEMPORAL_RELOAD_SIGNAL",
|
|
135
128
|
type: :string,
|
|
136
|
-
description: "Signal used by workers to
|
|
129
|
+
description: "Signal used by workers to rebuild the Temporal client manually, picking up " \
|
|
130
|
+
"rotated TLS material and a rotated API key"
|
|
137
131
|
},
|
|
138
132
|
|
|
139
133
|
api_key: {
|
|
@@ -151,19 +145,20 @@ module ActiveJob
|
|
|
151
145
|
"projected Kubernetes ServiceAccount token. An explicit api_key takes precedence"
|
|
152
146
|
},
|
|
153
147
|
|
|
154
|
-
|
|
155
|
-
default:
|
|
156
|
-
env_var: "
|
|
148
|
+
credential_watch: {
|
|
149
|
+
default: true,
|
|
150
|
+
env_var: "ACTIVEJOB_TEMPORAL_CREDENTIAL_WATCH",
|
|
157
151
|
type: :boolean,
|
|
158
|
-
description: "
|
|
159
|
-
"
|
|
152
|
+
description: "Keep every configured credential file fresh: api_key_file and the TLS " \
|
|
153
|
+
"certificate paths. A file path exists because the credential rotates, so " \
|
|
154
|
+
"this is on by default and watches whatever paths are configured"
|
|
160
155
|
},
|
|
161
156
|
|
|
162
157
|
credential_poll_interval: {
|
|
163
158
|
default: 30,
|
|
164
159
|
env_var: "ACTIVEJOB_TEMPORAL_CREDENTIAL_POLL_INTERVAL",
|
|
165
160
|
type: :integer,
|
|
166
|
-
description: "Seconds between credential file checks when
|
|
161
|
+
description: "Seconds between credential file checks when credential_watch is enabled"
|
|
167
162
|
},
|
|
168
163
|
|
|
169
164
|
credential_file_events: {
|
|
@@ -661,7 +656,7 @@ module ActiveJob
|
|
|
661
656
|
#
|
|
662
657
|
# @see ActiveJob::Temporal::Configuration.validate!
|
|
663
658
|
# @api private
|
|
664
|
-
# rubocop:disable Metrics/ClassLength
|
|
659
|
+
# rubocop:disable-next Metrics/ClassLength
|
|
665
660
|
class ConfigValidator
|
|
666
661
|
include ActiveModel::Validations
|
|
667
662
|
|
|
@@ -1054,8 +1049,18 @@ module ActiveJob
|
|
|
1054
1049
|
validate_tls_file_path(:tls_key_path)
|
|
1055
1050
|
validate_tls_file_path(:tls_server_root_ca_cert_path)
|
|
1056
1051
|
validate_tls_domain
|
|
1057
|
-
|
|
1058
|
-
|
|
1052
|
+
validate_tls_decision
|
|
1053
|
+
validate_reload_signal
|
|
1054
|
+
end
|
|
1055
|
+
|
|
1056
|
+
# The Temporal SDK turns TLS on by itself whenever an api_key is present, so leaving `tls`
|
|
1057
|
+
# unset silently couples transport security to an unrelated setting - and fails at connect
|
|
1058
|
+
# against a plaintext in-cluster frontend. Make the caller state the intent instead.
|
|
1059
|
+
def validate_tls_decision
|
|
1060
|
+
return unless tls.nil?
|
|
1061
|
+
return if api_key.to_s.strip.empty? && api_key_file.to_s.strip.empty?
|
|
1062
|
+
|
|
1063
|
+
errors.add(:tls, :requires_explicit_choice)
|
|
1059
1064
|
end
|
|
1060
1065
|
|
|
1061
1066
|
def validate_tls_cert_key_pair
|
|
@@ -1084,31 +1089,15 @@ module ActiveJob
|
|
|
1084
1089
|
errors.add(:tls_domain, :blank)
|
|
1085
1090
|
end
|
|
1086
1091
|
|
|
1087
|
-
def validate_tls_cert_watch
|
|
1088
|
-
unless [true, false].include?(tls_cert_watch)
|
|
1089
|
-
errors.add(:tls_cert_watch, :not_boolean, value: tls_cert_watch.inspect)
|
|
1090
|
-
return
|
|
1091
|
-
end
|
|
1092
|
-
|
|
1093
|
-
return unless tls_cert_watch && tls_watch_paths.empty?
|
|
1094
|
-
|
|
1095
|
-
errors.add(:tls_cert_watch, :requires_paths)
|
|
1096
|
-
end
|
|
1097
|
-
|
|
1098
1092
|
def validate_api_key_settings
|
|
1099
1093
|
validate_tls_file_path(:api_key_file)
|
|
1100
|
-
|
|
1101
|
-
unless [true, false].include?(api_key_watch)
|
|
1102
|
-
errors.add(:api_key_watch, :not_boolean, value: api_key_watch.inspect)
|
|
1103
|
-
return
|
|
1104
|
-
end
|
|
1105
|
-
|
|
1106
|
-
return unless api_key_watch && api_key_file.to_s.strip.empty?
|
|
1107
|
-
|
|
1108
|
-
errors.add(:api_key_watch, :requires_path)
|
|
1109
1094
|
end
|
|
1110
1095
|
|
|
1111
1096
|
def validate_credential_refresh_settings
|
|
1097
|
+
unless [true, false].include?(credential_watch)
|
|
1098
|
+
errors.add(:credential_watch, :not_boolean, value: credential_watch.inspect)
|
|
1099
|
+
end
|
|
1100
|
+
|
|
1112
1101
|
unless [true, false].include?(credential_file_events)
|
|
1113
1102
|
errors.add(:credential_file_events, :not_boolean, value: credential_file_events.inspect)
|
|
1114
1103
|
end
|
|
@@ -1129,20 +1118,16 @@ module ActiveJob
|
|
|
1129
1118
|
errors.add(:worker_activejob_workloads, :requires_activities)
|
|
1130
1119
|
end
|
|
1131
1120
|
|
|
1132
|
-
def
|
|
1133
|
-
unless
|
|
1134
|
-
errors.add(:
|
|
1121
|
+
def validate_reload_signal
|
|
1122
|
+
unless reload_signal.is_a?(String) && reload_signal.strip.present?
|
|
1123
|
+
errors.add(:reload_signal, :blank)
|
|
1135
1124
|
return
|
|
1136
1125
|
end
|
|
1137
1126
|
|
|
1138
|
-
normalized_signal =
|
|
1127
|
+
normalized_signal = reload_signal.sub(/\ASIG/i, "").upcase
|
|
1139
1128
|
return if Signal.list.key?(normalized_signal) && !UNTRAPPABLE_SIGNALS.include?(normalized_signal)
|
|
1140
1129
|
|
|
1141
|
-
errors.add(:
|
|
1142
|
-
end
|
|
1143
|
-
|
|
1144
|
-
def tls_watch_paths
|
|
1145
|
-
[tls_cert_path, tls_key_path, tls_server_root_ca_cert_path].compact.reject { |path| path.to_s.strip.empty? }
|
|
1130
|
+
errors.add(:reload_signal, :invalid, value: reload_signal.inspect)
|
|
1146
1131
|
end
|
|
1147
1132
|
|
|
1148
1133
|
def callable_accepts_positional_job?(callable)
|
|
@@ -1212,7 +1197,5 @@ module ActiveJob
|
|
|
1212
1197
|
nil
|
|
1213
1198
|
end
|
|
1214
1199
|
end
|
|
1215
|
-
# rubocop:enable Metrics/ClassLength
|
|
1216
1200
|
end
|
|
1217
1201
|
end
|
|
1218
|
-
# rubocop:enable Metrics/ModuleLength
|
|
@@ -40,29 +40,40 @@ module ActiveJob
|
|
|
40
40
|
Source = Struct.new(:name, :paths, :on_change, keyword_init: true)
|
|
41
41
|
|
|
42
42
|
class << self
|
|
43
|
-
# Builds a refresher
|
|
44
|
-
#
|
|
45
|
-
#
|
|
43
|
+
# Builds a refresher for every credential file the configuration names. A path is only
|
|
44
|
+
# configured because the credential behind it rotates, so `credential_watch` gates the
|
|
45
|
+
# whole mechanism rather than each file individually.
|
|
46
|
+
#
|
|
47
|
+
# A token refresh mutates the live connection, so it is the same call in every process.
|
|
48
|
+
# A certificate refresh is not: the default rebuilds the memoized client, which is right
|
|
49
|
+
# for an enqueue-side process but wrong inside a worker.
|
|
50
|
+
#
|
|
51
|
+
# @note A process running a `Temporalio::Worker` MUST pass `on_tls_change`. The worker holds
|
|
52
|
+
# its own client reference, and the default `reload_client!` closes the client it replaces
|
|
53
|
+
# - which is the one the worker is still polling on. Pass a callback that assigns the fresh
|
|
54
|
+
# client to the worker, as {WorkerClientReloader} does.
|
|
46
55
|
#
|
|
47
56
|
# @param configuration [Configuration] the gem configuration
|
|
48
|
-
# @param on_tls_change [#call] invoked when any TLS file changes
|
|
49
|
-
# @param on_api_key_change [#call] invoked when the API key file changes
|
|
57
|
+
# @param on_tls_change [#call] invoked when any TLS file changes; see the note above
|
|
50
58
|
# @param logger [#log_event, #warn, #error] structured logger
|
|
51
59
|
# @param listener_factory [#to, nil] injection point for tests, defaults to `Listen`
|
|
52
|
-
# @return [CredentialRefresher] a refresher with no sources when
|
|
60
|
+
# @return [CredentialRefresher] a refresher with no sources when no credential file is
|
|
61
|
+
# configured, or when `credential_watch` is off
|
|
53
62
|
def from_config(configuration,
|
|
54
63
|
on_tls_change: -> { ActiveJob::Temporal.reload_client! },
|
|
55
|
-
on_api_key_change: -> { ActiveJob::Temporal.refresh_api_key! },
|
|
56
64
|
logger: ActiveJob::Temporal::Logger,
|
|
57
65
|
listener_factory: nil)
|
|
58
66
|
sources = []
|
|
59
67
|
|
|
60
|
-
if configuration.
|
|
61
|
-
|
|
62
|
-
|
|
68
|
+
if configuration.credential_watch
|
|
69
|
+
tls = tls_paths(configuration)
|
|
70
|
+
sources << Source.new(name: "tls", paths: tls, on_change: on_tls_change) if tls.any?
|
|
63
71
|
|
|
64
|
-
|
|
65
|
-
|
|
72
|
+
token = configuration.api_key_file.to_s.strip
|
|
73
|
+
if token.present?
|
|
74
|
+
sources << Source.new(name: "api_key", paths: [token],
|
|
75
|
+
on_change: -> { ActiveJob::Temporal.refresh_api_key! })
|
|
76
|
+
end
|
|
66
77
|
end
|
|
67
78
|
|
|
68
79
|
new(
|
|
@@ -44,12 +44,11 @@ module ActiveJob
|
|
|
44
44
|
workflow_id
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
# rubocop:disable Naming/PredicateMethod
|
|
47
|
+
# rubocop:disable-next Naming/PredicateMethod
|
|
48
48
|
def discard(job_class, job_id, reason: nil, client: ActiveJob::Temporal.client)
|
|
49
49
|
handle_for(job_class, job_id, client: client).signal(:discard, reason)
|
|
50
50
|
true
|
|
51
51
|
end
|
|
52
|
-
# rubocop:enable Naming/PredicateMethod
|
|
53
52
|
|
|
54
53
|
def workflow_id(job_class, job_id)
|
|
55
54
|
class_name = job_class.is_a?(Class) ? job_class.name : job_class.to_s
|
|
@@ -11,7 +11,7 @@ require_relative "retry_mapper"
|
|
|
11
11
|
|
|
12
12
|
module ActiveJob
|
|
13
13
|
module Temporal
|
|
14
|
-
# rubocop:disable Metrics/ClassLength
|
|
14
|
+
# rubocop:disable-next Metrics/ClassLength
|
|
15
15
|
class JobPayloadBuilder
|
|
16
16
|
include JobPayloadChildWorkflows
|
|
17
17
|
include JobPayloadChainBuilder
|
|
@@ -204,6 +204,5 @@ module ActiveJob
|
|
|
204
204
|
value
|
|
205
205
|
end
|
|
206
206
|
end
|
|
207
|
-
# rubocop:enable Metrics/ClassLength
|
|
208
207
|
end
|
|
209
208
|
end
|
|
@@ -129,11 +129,10 @@ en:
|
|
|
129
129
|
tls_domain:
|
|
130
130
|
blank: "must be present when configured"
|
|
131
131
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
requires_paths: "requires at least one TLS certificate path to watch"
|
|
132
|
+
tls:
|
|
133
|
+
requires_explicit_choice: "must be set explicitly to true, false, or TLS options when api_key or api_key_file is configured - the Temporal SDK enables TLS on its own whenever an API key is present, which fails the handshake against a plaintext frontend"
|
|
135
134
|
|
|
136
|
-
|
|
135
|
+
reload_signal:
|
|
137
136
|
blank: "must be present when configured"
|
|
138
137
|
invalid: "must be a signal name like HUP or USR1, got: %{value}"
|
|
139
138
|
|
|
@@ -141,9 +140,8 @@ en:
|
|
|
141
140
|
invalid_path: "must be a non-empty file path, got: %{value}"
|
|
142
141
|
unreadable_path: "must resolve to a readable regular file, got: %{value}"
|
|
143
142
|
|
|
144
|
-
|
|
143
|
+
credential_watch:
|
|
145
144
|
not_boolean: "must be true or false, got: %{value}"
|
|
146
|
-
requires_path: "requires api_key_file to watch"
|
|
147
145
|
|
|
148
146
|
credential_poll_interval:
|
|
149
147
|
invalid: "must be a positive number of seconds, got: %{value}"
|
|
@@ -5,7 +5,7 @@ require_relative "../observability"
|
|
|
5
5
|
module ActiveJob
|
|
6
6
|
module Temporal
|
|
7
7
|
module Observability
|
|
8
|
-
# rubocop:disable Metrics/ClassLength
|
|
8
|
+
# rubocop:disable-next Metrics/ClassLength
|
|
9
9
|
class Datadog < Adapter
|
|
10
10
|
attr_accessor :service, :statsd_host, :statsd_port
|
|
11
11
|
attr_writer :statsd
|
|
@@ -156,7 +156,6 @@ module ActiveJob
|
|
|
156
156
|
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
157
157
|
end
|
|
158
158
|
end
|
|
159
|
-
# rubocop:enable Metrics/ClassLength
|
|
160
159
|
end
|
|
161
160
|
end
|
|
162
161
|
end
|
|
@@ -50,7 +50,7 @@ module ActiveJob
|
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
-
# rubocop:disable Metrics/ClassLength
|
|
53
|
+
# rubocop:disable-next Metrics/ClassLength
|
|
54
54
|
class Prometheus < Adapter
|
|
55
55
|
DURATION_BUCKETS = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 30, 60, 120].freeze
|
|
56
56
|
PAYLOAD_SIZE_BUCKETS = [512, 1024, 2_048, 4_096, 8_192, 16_384, 32_768, 65_536, 131_072, 262_144,
|
|
@@ -260,7 +260,6 @@ module ActiveJob
|
|
|
260
260
|
(value || "unknown").to_s
|
|
261
261
|
end
|
|
262
262
|
end
|
|
263
|
-
# rubocop:enable Metrics/ClassLength
|
|
264
263
|
end
|
|
265
264
|
end
|
|
266
265
|
end
|
|
@@ -30,7 +30,7 @@ module ActiveJob
|
|
|
30
30
|
# @example Extracting discard handlers
|
|
31
31
|
# discard_handlers = extractor.discard_handlers(MyJob)
|
|
32
32
|
# # => [{ exception: ActiveRecord::RecordNotFound, handler: ... }]
|
|
33
|
-
# rubocop:disable Metrics/ClassLength
|
|
33
|
+
# rubocop:disable-next Metrics/ClassLength
|
|
34
34
|
class RetryHandlerExtractor
|
|
35
35
|
def initialize
|
|
36
36
|
@cache_mutex = Mutex.new
|
|
@@ -371,6 +371,5 @@ module ActiveJob
|
|
|
371
371
|
candidate_class <= handler_class
|
|
372
372
|
end
|
|
373
373
|
end
|
|
374
|
-
# rubocop:enable Metrics/ClassLength
|
|
375
374
|
end
|
|
376
375
|
end
|
|
@@ -53,7 +53,7 @@ module ActiveJob
|
|
|
53
53
|
heartbeat_timeout
|
|
54
54
|
].freeze
|
|
55
55
|
|
|
56
|
-
# rubocop:disable Metrics/BlockLength
|
|
56
|
+
# rubocop:disable-next Metrics/BlockLength
|
|
57
57
|
class_methods do
|
|
58
58
|
# Define Temporal activity timeout options for this job class.
|
|
59
59
|
#
|
|
@@ -130,7 +130,6 @@ module ActiveJob
|
|
|
130
130
|
end
|
|
131
131
|
end
|
|
132
132
|
end
|
|
133
|
-
# rubocop:enable Metrics/BlockLength
|
|
134
133
|
end
|
|
135
134
|
end
|
|
136
135
|
end
|
|
@@ -6,7 +6,7 @@ require_relative "bind_policy"
|
|
|
6
6
|
|
|
7
7
|
module ActiveJob
|
|
8
8
|
module Temporal
|
|
9
|
-
# rubocop:disable Metrics/ClassLength
|
|
9
|
+
# rubocop:disable-next Metrics/ClassLength
|
|
10
10
|
class WorkerPool
|
|
11
11
|
Child = Data.define(:pid, :index, :restarts)
|
|
12
12
|
|
|
@@ -416,6 +416,5 @@ module ActiveJob
|
|
|
416
416
|
end
|
|
417
417
|
end
|
|
418
418
|
end
|
|
419
|
-
# rubocop:enable Metrics/ClassLength
|
|
420
419
|
end
|
|
421
420
|
end
|
|
@@ -25,7 +25,7 @@ module ActiveJob
|
|
|
25
25
|
# config = ActiveJob::Temporal.config
|
|
26
26
|
# enqueuer = WorkflowEnqueuer.new(client, config)
|
|
27
27
|
# enqueuer.enqueue(job)
|
|
28
|
-
# rubocop:disable Metrics/ClassLength
|
|
28
|
+
# rubocop:disable-next Metrics/ClassLength
|
|
29
29
|
class WorkflowEnqueuer
|
|
30
30
|
include WorkflowEnqueuerBatch
|
|
31
31
|
|
|
@@ -267,6 +267,5 @@ module ActiveJob
|
|
|
267
267
|
raise ArgumentError, "scheduled_at must be an ISO8601 string or respond to to_time"
|
|
268
268
|
end
|
|
269
269
|
end
|
|
270
|
-
# rubocop:enable Metrics/ClassLength
|
|
271
270
|
end
|
|
272
271
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: activejob-temporal
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Temporal Technologies
|
|
@@ -87,7 +87,7 @@ dependencies:
|
|
|
87
87
|
version: 1.4.0
|
|
88
88
|
- - "<"
|
|
89
89
|
- !ruby/object:Gem::Version
|
|
90
|
-
version: '1.
|
|
90
|
+
version: '1.12'
|
|
91
91
|
type: :runtime
|
|
92
92
|
prerelease: false
|
|
93
93
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -97,7 +97,7 @@ dependencies:
|
|
|
97
97
|
version: 1.4.0
|
|
98
98
|
- - "<"
|
|
99
99
|
- !ruby/object:Gem::Version
|
|
100
|
-
version: '1.
|
|
100
|
+
version: '1.12'
|
|
101
101
|
- !ruby/object:Gem::Dependency
|
|
102
102
|
name: benchmark-ips
|
|
103
103
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -222,14 +222,14 @@ dependencies:
|
|
|
222
222
|
requirements:
|
|
223
223
|
- - "~>"
|
|
224
224
|
- !ruby/object:Gem::Version
|
|
225
|
-
version: '1.
|
|
225
|
+
version: '1.92'
|
|
226
226
|
type: :development
|
|
227
227
|
prerelease: false
|
|
228
228
|
version_requirements: !ruby/object:Gem::Requirement
|
|
229
229
|
requirements:
|
|
230
230
|
- - "~>"
|
|
231
231
|
- !ruby/object:Gem::Version
|
|
232
|
-
version: '1.
|
|
232
|
+
version: '1.92'
|
|
233
233
|
- !ruby/object:Gem::Dependency
|
|
234
234
|
name: simplecov
|
|
235
235
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -413,7 +413,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
413
413
|
- !ruby/object:Gem::Version
|
|
414
414
|
version: '0'
|
|
415
415
|
requirements: []
|
|
416
|
-
rubygems_version: 4.0.
|
|
416
|
+
rubygems_version: 4.0.20
|
|
417
417
|
specification_version: 4
|
|
418
418
|
summary: Rails ActiveJob adapter backed by Temporal Workflows
|
|
419
419
|
test_files: []
|