tasker-rb 0.1.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 +7 -0
- data/DEVELOPMENT.md +548 -0
- data/README.md +87 -0
- data/ext/tasker_core/Cargo.lock +4720 -0
- data/ext/tasker_core/Cargo.toml +76 -0
- data/ext/tasker_core/extconf.rb +38 -0
- data/ext/tasker_core/src/CLAUDE.md +7 -0
- data/ext/tasker_core/src/bootstrap.rs +320 -0
- data/ext/tasker_core/src/bridge.rs +400 -0
- data/ext/tasker_core/src/client_ffi.rs +173 -0
- data/ext/tasker_core/src/conversions.rs +131 -0
- data/ext/tasker_core/src/diagnostics.rs +57 -0
- data/ext/tasker_core/src/event_handler.rs +179 -0
- data/ext/tasker_core/src/event_publisher_ffi.rs +239 -0
- data/ext/tasker_core/src/ffi_logging.rs +245 -0
- data/ext/tasker_core/src/global_event_system.rs +16 -0
- data/ext/tasker_core/src/in_process_event_ffi.rs +319 -0
- data/ext/tasker_core/src/lib.rs +41 -0
- data/ext/tasker_core/src/observability_ffi.rs +339 -0
- data/lib/tasker_core/batch_processing/batch_aggregation_scenario.rb +85 -0
- data/lib/tasker_core/batch_processing/batch_worker_context.rb +238 -0
- data/lib/tasker_core/bootstrap.rb +394 -0
- data/lib/tasker_core/domain_events/base_publisher.rb +220 -0
- data/lib/tasker_core/domain_events/base_subscriber.rb +178 -0
- data/lib/tasker_core/domain_events/publisher_registry.rb +253 -0
- data/lib/tasker_core/domain_events/subscriber_registry.rb +152 -0
- data/lib/tasker_core/domain_events.rb +43 -0
- data/lib/tasker_core/errors/CLAUDE.md +7 -0
- data/lib/tasker_core/errors/common.rb +305 -0
- data/lib/tasker_core/errors/error_classifier.rb +61 -0
- data/lib/tasker_core/errors.rb +4 -0
- data/lib/tasker_core/event_bridge.rb +330 -0
- data/lib/tasker_core/handlers.rb +159 -0
- data/lib/tasker_core/internal.rb +31 -0
- data/lib/tasker_core/logger.rb +234 -0
- data/lib/tasker_core/models.rb +337 -0
- data/lib/tasker_core/observability/types.rb +158 -0
- data/lib/tasker_core/observability.rb +292 -0
- data/lib/tasker_core/registry/handler_registry.rb +453 -0
- data/lib/tasker_core/registry/resolver_chain.rb +258 -0
- data/lib/tasker_core/registry/resolvers/base_resolver.rb +90 -0
- data/lib/tasker_core/registry/resolvers/class_constant_resolver.rb +156 -0
- data/lib/tasker_core/registry/resolvers/explicit_mapping_resolver.rb +146 -0
- data/lib/tasker_core/registry/resolvers/method_dispatch_wrapper.rb +144 -0
- data/lib/tasker_core/registry/resolvers/registry_resolver.rb +229 -0
- data/lib/tasker_core/registry/resolvers.rb +42 -0
- data/lib/tasker_core/registry.rb +12 -0
- data/lib/tasker_core/step_handler/api.rb +48 -0
- data/lib/tasker_core/step_handler/base.rb +354 -0
- data/lib/tasker_core/step_handler/batchable.rb +50 -0
- data/lib/tasker_core/step_handler/decision.rb +53 -0
- data/lib/tasker_core/step_handler/mixins/api.rb +452 -0
- data/lib/tasker_core/step_handler/mixins/batchable.rb +465 -0
- data/lib/tasker_core/step_handler/mixins/decision.rb +252 -0
- data/lib/tasker_core/step_handler/mixins.rb +66 -0
- data/lib/tasker_core/subscriber.rb +212 -0
- data/lib/tasker_core/task_handler/base.rb +254 -0
- data/lib/tasker_core/tasker_rb.so +0 -0
- data/lib/tasker_core/template_discovery.rb +181 -0
- data/lib/tasker_core/tracing.rb +166 -0
- data/lib/tasker_core/types/batch_processing_outcome.rb +301 -0
- data/lib/tasker_core/types/client_types.rb +145 -0
- data/lib/tasker_core/types/decision_point_outcome.rb +177 -0
- data/lib/tasker_core/types/error_types.rb +72 -0
- data/lib/tasker_core/types/simple_message.rb +151 -0
- data/lib/tasker_core/types/step_context.rb +328 -0
- data/lib/tasker_core/types/step_handler_call_result.rb +307 -0
- data/lib/tasker_core/types/step_message.rb +112 -0
- data/lib/tasker_core/types/step_types.rb +207 -0
- data/lib/tasker_core/types/task_template.rb +240 -0
- data/lib/tasker_core/types/task_types.rb +148 -0
- data/lib/tasker_core/types.rb +132 -0
- data/lib/tasker_core/version.rb +13 -0
- data/lib/tasker_core/worker/CLAUDE.md +7 -0
- data/lib/tasker_core/worker/event_poller.rb +224 -0
- data/lib/tasker_core/worker/in_process_domain_event_poller.rb +271 -0
- data/lib/tasker_core.rb +160 -0
- metadata +322 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TaskerCore
|
|
4
|
+
module Models
|
|
5
|
+
# Wrapper for TaskSequenceStep data received from Rust FFI.
|
|
6
|
+
#
|
|
7
|
+
# This class provides a Ruby-friendly interface to the complete step execution context,
|
|
8
|
+
# including task metadata, workflow step state, dependency results, and step definition.
|
|
9
|
+
# The data structure is provided by the Rust orchestration system via FFI when a step
|
|
10
|
+
# is ready for execution.
|
|
11
|
+
#
|
|
12
|
+
# @example Accessing task context in a handler
|
|
13
|
+
# def call(context)
|
|
14
|
+
# even_number = context.task.context['even_number']
|
|
15
|
+
# # or use the convenience method
|
|
16
|
+
# even_number = context.get_task_field('even_number')
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
# @example Accessing dependency results
|
|
20
|
+
# def call(context)
|
|
21
|
+
# previous_result = context.get_dependency_result('previous_step_name')
|
|
22
|
+
# end
|
|
23
|
+
class TaskSequenceStepWrapper
|
|
24
|
+
# @return [TaskWrapper] Wrapped task with context and metadata
|
|
25
|
+
# @return [WorkflowStepWrapper] Wrapped workflow step with execution state
|
|
26
|
+
# @return [DependencyResultsWrapper] Results from parent steps
|
|
27
|
+
# @return [StepDefinitionWrapper] Step definition from task template
|
|
28
|
+
attr_reader :task, :workflow_step, :dependency_results, :step_definition
|
|
29
|
+
|
|
30
|
+
# Creates a new TaskSequenceStepWrapper from FFI data
|
|
31
|
+
#
|
|
32
|
+
# @param step_data [Hash] The complete step execution data from Rust
|
|
33
|
+
# @option step_data [Hash] :task Task and namespace metadata
|
|
34
|
+
# @option step_data [Hash] :workflow_step Step execution state and results
|
|
35
|
+
# @option step_data [Hash] :dependency_results Results from parent steps
|
|
36
|
+
# @option step_data [Hash] :step_definition Step configuration from template
|
|
37
|
+
def initialize(step_data)
|
|
38
|
+
@task = TaskWrapper.new(step_data[:task])
|
|
39
|
+
@workflow_step = WorkflowStepWrapper.new(step_data[:workflow_step])
|
|
40
|
+
@dependency_results = DependencyResultsWrapper.new(step_data[:dependency_results])
|
|
41
|
+
@step_definition = StepDefinitionWrapper.new(step_data[:step_definition])
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Convenience method to access task context fields
|
|
45
|
+
#
|
|
46
|
+
# @param field_name [String, Symbol] The field name in task context
|
|
47
|
+
# @return [Object, nil] The field value or nil if not found
|
|
48
|
+
#
|
|
49
|
+
# @example
|
|
50
|
+
# sequence.get_task_field('even_number') # => 2
|
|
51
|
+
def get_task_field(field_name)
|
|
52
|
+
@task.context[field_name.to_s]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Convenience method to access dependency results
|
|
56
|
+
#
|
|
57
|
+
# @param step_name [String, Symbol] The name of the parent step
|
|
58
|
+
# @return [Object, nil] The result from the parent step or nil
|
|
59
|
+
#
|
|
60
|
+
# @example
|
|
61
|
+
# result = sequence.get_dependency_result('linear_step_1') # => 36
|
|
62
|
+
def get_dependency_result(step_name)
|
|
63
|
+
@dependency_results.get_result(step_name)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Convenience method to access dependency results (alias for compatibility)
|
|
67
|
+
#
|
|
68
|
+
# @param step_name [String, Symbol] The name of the parent step
|
|
69
|
+
# @return [Object, nil] The result from the parent step or nil
|
|
70
|
+
#
|
|
71
|
+
# @example
|
|
72
|
+
# result = sequence.get_results('linear_step_1') # => 36
|
|
73
|
+
def get_results(step_name)
|
|
74
|
+
@dependency_results.get_results(step_name)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Wrapper for task metadata and context.
|
|
79
|
+
#
|
|
80
|
+
# Handles the nested task structure from Rust FFI where the actual task data
|
|
81
|
+
# is nested under a :task key within the parent task hash.
|
|
82
|
+
#
|
|
83
|
+
# @example Accessing task properties
|
|
84
|
+
# task.task_uuid # => "0199a46a-11a8-7d53-83da-0b13513dab49"
|
|
85
|
+
# task.context # => { "even_number" => 2 }
|
|
86
|
+
# task.namespace_name # => "linear_workflow"
|
|
87
|
+
class TaskWrapper
|
|
88
|
+
# @return [String] UUID v7 of the task instance
|
|
89
|
+
# @return [ActiveSupport::HashWithIndifferentAccess] Task context with input data and accumulated state
|
|
90
|
+
# @return [String] Namespace name from task template
|
|
91
|
+
# @return [String] Task template name
|
|
92
|
+
# @return [String] Task template version
|
|
93
|
+
attr_reader :task_uuid, :context, :namespace_name, :task_name, :task_version
|
|
94
|
+
|
|
95
|
+
# Creates a new TaskWrapper from FFI data
|
|
96
|
+
#
|
|
97
|
+
# @param task_data [Hash] Task data with nested structure from Rust
|
|
98
|
+
# @option task_data [Hash] :task Nested task object with context
|
|
99
|
+
# @option task_data [String] :task_name Template name
|
|
100
|
+
# @option task_data [String] :namespace_name Namespace from template
|
|
101
|
+
# @option task_data [String] :task_version Template version
|
|
102
|
+
def initialize(task_data)
|
|
103
|
+
# Handle nested task structure from Rust FFI
|
|
104
|
+
# Data comes as: { task: { task_uuid: ..., context: ... }, task_name: "...", namespace_name: "..." }
|
|
105
|
+
# The actual task fields are nested under :task key
|
|
106
|
+
inner_task = task_data[:task] || task_data
|
|
107
|
+
|
|
108
|
+
@task_uuid = inner_task[:task_uuid]
|
|
109
|
+
# Use HashWithIndifferentAccess for developer-friendly context access
|
|
110
|
+
@context = (inner_task[:context] || {}).with_indifferent_access
|
|
111
|
+
@namespace_name = task_data[:namespace_name] || inner_task[:namespace_name]
|
|
112
|
+
@task_name = task_data[:task_name] || inner_task[:task_name]
|
|
113
|
+
@task_version = task_data[:task_version] || inner_task[:task_version]
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Wrapper for workflow step execution state and metadata.
|
|
118
|
+
#
|
|
119
|
+
# Provides access to step execution tracking, retry configuration, and results.
|
|
120
|
+
#
|
|
121
|
+
# @example Checking step state
|
|
122
|
+
# step.name # => "linear_step_1"
|
|
123
|
+
# step.attempts # => 1
|
|
124
|
+
# step.max_attempts # => 3
|
|
125
|
+
# step.in_process # => false
|
|
126
|
+
class WorkflowStepWrapper
|
|
127
|
+
# @return [String] UUID v7 of the workflow step instance
|
|
128
|
+
# @return [String] UUID v7 of the task this step belongs to
|
|
129
|
+
# @return [String] UUID v7 of the named step definition
|
|
130
|
+
# @return [String] Step name from template
|
|
131
|
+
# @return [Boolean] Whether step can be retried
|
|
132
|
+
# @return [Integer] Maximum retry attempts
|
|
133
|
+
# @return [Boolean] Whether step is currently being processed
|
|
134
|
+
# @return [Boolean] Whether step has been processed
|
|
135
|
+
# @return [Time, nil] When step was last processed
|
|
136
|
+
# @return [Integer] Number of execution attempts
|
|
137
|
+
# @return [Time, nil] When step was last attempted
|
|
138
|
+
# @return [Integer] Backoff delay in seconds for retry
|
|
139
|
+
# @return [ActiveSupport::HashWithIndifferentAccess] Step inputs from template
|
|
140
|
+
# @return [ActiveSupport::HashWithIndifferentAccess] Step execution results
|
|
141
|
+
|
|
142
|
+
# @return [Time] When step was created
|
|
143
|
+
# @return [Time] When step was last updated
|
|
144
|
+
# @return [ActiveSupport::HashWithIndifferentAccess, nil] TAS-125: Checkpoint data for batch processing resumption
|
|
145
|
+
attr_reader :workflow_step_uuid, :task_uuid, :named_step_uuid, :name,
|
|
146
|
+
:retryable, :max_attempts, :in_process, :processed, :processed_at,
|
|
147
|
+
:attempts, :last_attempted_at, :backoff_request_seconds,
|
|
148
|
+
:inputs, :results, :created_at, :updated_at, :checkpoint
|
|
149
|
+
|
|
150
|
+
# Creates a new WorkflowStepWrapper from FFI data
|
|
151
|
+
#
|
|
152
|
+
# @param step_data [Hash] Workflow step data from Rust
|
|
153
|
+
def initialize(step_data)
|
|
154
|
+
@workflow_step_uuid = step_data[:workflow_step_uuid]
|
|
155
|
+
@task_uuid = step_data[:task_uuid]
|
|
156
|
+
@named_step_uuid = step_data[:named_step_uuid]
|
|
157
|
+
@name = step_data[:name]
|
|
158
|
+
@retryable = step_data[:retryable]
|
|
159
|
+
@max_attempts = step_data[:max_attempts]
|
|
160
|
+
@in_process = step_data[:in_process]
|
|
161
|
+
@processed = step_data[:processed]
|
|
162
|
+
@processed_at = step_data[:processed_at]
|
|
163
|
+
@attempts = step_data[:attempts]
|
|
164
|
+
@last_attempted_at = step_data[:last_attempted_at]
|
|
165
|
+
@backoff_request_seconds = step_data[:backoff_request_seconds]
|
|
166
|
+
# Use HashWithIndifferentAccess for nested hashes
|
|
167
|
+
@inputs = (step_data[:inputs] || {}).with_indifferent_access
|
|
168
|
+
@results = (step_data[:results] || {}).with_indifferent_access
|
|
169
|
+
|
|
170
|
+
@created_at = step_data[:created_at]
|
|
171
|
+
@updated_at = step_data[:updated_at]
|
|
172
|
+
# TAS-125: Checkpoint data for batch processing resumption
|
|
173
|
+
@checkpoint = step_data[:checkpoint]&.with_indifferent_access
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Wrapper for dependency results from parent steps.
|
|
178
|
+
#
|
|
179
|
+
# Provides access to results from steps that this step depends on.
|
|
180
|
+
# Results are keyed by step name.
|
|
181
|
+
#
|
|
182
|
+
# @note Two methods for accessing results:
|
|
183
|
+
# - `get_result(name)` returns the full result hash with metadata
|
|
184
|
+
# - `get_results(name)` returns just the computed value (recommended for handlers)
|
|
185
|
+
#
|
|
186
|
+
# @example Accessing dependency results
|
|
187
|
+
# deps.get_results('previous_step') # => 36 (just the value)
|
|
188
|
+
# deps.get_result('previous_step') # => { result: 36, metadata: {...} }
|
|
189
|
+
# deps['previous_step'] # => { result: 36, metadata: {...} }
|
|
190
|
+
class DependencyResultsWrapper
|
|
191
|
+
# Creates a new DependencyResultsWrapper
|
|
192
|
+
#
|
|
193
|
+
# @param results_data [Hash] Hash of step names to their results
|
|
194
|
+
def initialize(results_data)
|
|
195
|
+
# Use HashWithIndifferentAccess for developer-friendly key access
|
|
196
|
+
@results = (results_data || {}).with_indifferent_access
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Get result from a parent step (returns full result hash)
|
|
200
|
+
#
|
|
201
|
+
# @param step_name [String, Symbol] Name of the parent step
|
|
202
|
+
# @return [Hash, nil] The full result hash or nil if not found
|
|
203
|
+
def get_result(step_name)
|
|
204
|
+
@results[step_name] # HashWithIndifferentAccess handles string/symbol automatically
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Get the actual result value from a parent step (extracts 'result' field)
|
|
208
|
+
#
|
|
209
|
+
# This is the typical method handlers use to get the actual computed value
|
|
210
|
+
# from a parent step, rather than the full result metadata hash.
|
|
211
|
+
#
|
|
212
|
+
# @param step_name [String, Symbol] Name of the parent step
|
|
213
|
+
# @return [Object, nil] The result value or nil if not found
|
|
214
|
+
#
|
|
215
|
+
# @example
|
|
216
|
+
# deps.get_results('linear_step_1') # => 36 (the actual value)
|
|
217
|
+
# deps.get_result('linear_step_1') # => { result: 36, metadata: {...} }
|
|
218
|
+
def get_results(step_name)
|
|
219
|
+
result_hash = @results[step_name]
|
|
220
|
+
return nil unless result_hash
|
|
221
|
+
|
|
222
|
+
# If it's a hash with a 'result' key, extract that value
|
|
223
|
+
# Otherwise return the whole thing (might be a primitive value)
|
|
224
|
+
if result_hash.is_a?(Hash) && result_hash.key?('result')
|
|
225
|
+
result_hash['result']
|
|
226
|
+
else
|
|
227
|
+
result_hash
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# Array-style access to dependency results
|
|
232
|
+
#
|
|
233
|
+
# @param step_name [String, Symbol] Name of the parent step
|
|
234
|
+
# @return [Hash, nil] The full result hash or nil if not found
|
|
235
|
+
def [](step_name)
|
|
236
|
+
get_result(step_name)
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Get all dependency result step names
|
|
240
|
+
#
|
|
241
|
+
# @return [Array<String>] List of step names that have results
|
|
242
|
+
def keys
|
|
243
|
+
@results.keys
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
# Check if a dependency result exists
|
|
247
|
+
#
|
|
248
|
+
# @param step_name [String, Symbol] Name of the parent step
|
|
249
|
+
# @return [Boolean] True if result exists
|
|
250
|
+
def key?(step_name)
|
|
251
|
+
@results.key?(step_name) # HashWithIndifferentAccess handles string/symbol automatically
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def each_key(&)
|
|
255
|
+
@results.keys.each(&)
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
# Wrapper for step definition from task template.
|
|
260
|
+
#
|
|
261
|
+
# Provides access to step configuration including handler specification,
|
|
262
|
+
# dependencies, retry policy, and timeout settings.
|
|
263
|
+
#
|
|
264
|
+
# @example Accessing step definition
|
|
265
|
+
# step_def.name # => "linear_step_1"
|
|
266
|
+
# step_def.description # => "Square the initial even number..."
|
|
267
|
+
# step_def.handler.callable # => "LinearWorkflow::StepHandlers::LinearStep1Handler"
|
|
268
|
+
# step_def.dependencies # => ["previous_step"]
|
|
269
|
+
# step_def.timeout_seconds # => 30
|
|
270
|
+
class StepDefinitionWrapper
|
|
271
|
+
# @return [String] Step name
|
|
272
|
+
# @return [String] Human-readable description
|
|
273
|
+
# @return [HandlerWrapper] Handler configuration
|
|
274
|
+
|
|
275
|
+
# @return [Array<String>] Names of parent steps this depends on
|
|
276
|
+
# @return [ActiveSupport::HashWithIndifferentAccess] Retry configuration
|
|
277
|
+
# @return [Integer] Timeout in seconds
|
|
278
|
+
# @return [Array<String>] Events this step publishes
|
|
279
|
+
attr_reader :name, :description, :handler,
|
|
280
|
+
:dependencies, :retry, :timeout_seconds, :publishes_events
|
|
281
|
+
|
|
282
|
+
# Creates a new StepDefinitionWrapper from template data
|
|
283
|
+
#
|
|
284
|
+
# @param definition_data [Hash] Step definition from task template
|
|
285
|
+
def initialize(definition_data)
|
|
286
|
+
@name = definition_data[:name]
|
|
287
|
+
@description = definition_data[:description]
|
|
288
|
+
@handler = HandlerWrapper.new(definition_data[:handler])
|
|
289
|
+
|
|
290
|
+
@dependencies = definition_data[:dependencies] || []
|
|
291
|
+
# Use HashWithIndifferentAccess for retry configuration
|
|
292
|
+
@retry = (definition_data[:retry] || {}).with_indifferent_access
|
|
293
|
+
@timeout_seconds = definition_data[:timeout_seconds]
|
|
294
|
+
@publishes_events = definition_data[:publishes_events] || []
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
# Wrapper for handler configuration.
|
|
299
|
+
#
|
|
300
|
+
# Provides access to handler class name, method dispatch, resolver hints,
|
|
301
|
+
# and initialization parameters from the task template.
|
|
302
|
+
#
|
|
303
|
+
# TAS-93: Extended to support method dispatch and resolver hints from
|
|
304
|
+
# the Rust HandlerDefinition struct.
|
|
305
|
+
#
|
|
306
|
+
# @example Accessing handler configuration
|
|
307
|
+
# handler.callable # => "LinearWorkflow::StepHandlers::LinearStep1Handler"
|
|
308
|
+
# handler.initialization # => { operation: "square", step_number: 1 }
|
|
309
|
+
# handler.handler_method # => "refund" (or nil for default .call())
|
|
310
|
+
# handler.resolver # => "explicit" (or nil for chain traversal)
|
|
311
|
+
class HandlerWrapper
|
|
312
|
+
# @return [String] Fully-qualified handler class name
|
|
313
|
+
# @return [ActiveSupport::HashWithIndifferentAccess] Initialization parameters for the handler
|
|
314
|
+
# @return [String, nil] TAS-93: Method to invoke instead of default .call()
|
|
315
|
+
# @return [String, nil] TAS-93: Specific resolver to use (bypasses chain)
|
|
316
|
+
attr_reader :callable, :initialization, :handler_method, :resolver
|
|
317
|
+
|
|
318
|
+
# Creates a new HandlerWrapper from template data
|
|
319
|
+
#
|
|
320
|
+
# @param handler_data [Hash] Handler configuration from template
|
|
321
|
+
# @option handler_data [String] :callable Handler class name
|
|
322
|
+
# @option handler_data [Hash] :initialization Handler init params
|
|
323
|
+
# @option handler_data [String] :method TAS-93: Method to invoke (from Rust FFI)
|
|
324
|
+
# @option handler_data [String] :resolver TAS-93: Resolver hint (from Rust FFI)
|
|
325
|
+
def initialize(handler_data)
|
|
326
|
+
@callable = handler_data[:callable]
|
|
327
|
+
# Use HashWithIndifferentAccess for initialization parameters
|
|
328
|
+
@initialization = (handler_data[:initialization] || {}).with_indifferent_access
|
|
329
|
+
# TAS-93: Method dispatch - note Rust field is 'method' but we use 'handler_method'
|
|
330
|
+
# to avoid conflict with Ruby's Object#method
|
|
331
|
+
@handler_method = handler_data[:method]
|
|
332
|
+
# TAS-93: Resolver hint for direct resolver routing
|
|
333
|
+
@resolver = handler_data[:resolver]
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
end
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'dry-struct'
|
|
4
|
+
require 'dry-types'
|
|
5
|
+
|
|
6
|
+
module TaskerCore
|
|
7
|
+
module Observability
|
|
8
|
+
# Type definitions for observability data structures
|
|
9
|
+
#
|
|
10
|
+
# These types use dry-struct for automatic validation and provide
|
|
11
|
+
# structured access to health, metrics, and configuration data.
|
|
12
|
+
module Types
|
|
13
|
+
include Dry.Types()
|
|
14
|
+
|
|
15
|
+
# ==========================================================================
|
|
16
|
+
# Health Types
|
|
17
|
+
# ==========================================================================
|
|
18
|
+
|
|
19
|
+
# Basic health check response
|
|
20
|
+
class BasicHealth < Dry::Struct
|
|
21
|
+
attribute :status, Types::Strict::String
|
|
22
|
+
attribute :worker_id, Types::Strict::String
|
|
23
|
+
attribute :timestamp, Types::Strict::String
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Individual health check result
|
|
27
|
+
class HealthCheck < Dry::Struct
|
|
28
|
+
attribute :status, Types::Strict::String
|
|
29
|
+
attribute :message, Types::Strict::String.optional
|
|
30
|
+
attribute :duration_ms, Types::Strict::Integer
|
|
31
|
+
attribute :last_checked, Types::Strict::String
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Worker system information
|
|
35
|
+
class WorkerSystemInfo < Dry::Struct
|
|
36
|
+
attribute :version, Types::Strict::String
|
|
37
|
+
attribute :environment, Types::Strict::String
|
|
38
|
+
attribute :uptime_seconds, Types::Strict::Integer
|
|
39
|
+
attribute :worker_type, Types::Strict::String
|
|
40
|
+
attribute :database_pool_size, Types::Strict::Integer
|
|
41
|
+
attribute :command_processor_active, Types::Strict::Bool
|
|
42
|
+
attribute :supported_namespaces, Types::Strict::Array.of(Types::Strict::String)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Detailed health check response
|
|
46
|
+
class DetailedHealth < Dry::Struct
|
|
47
|
+
attribute :status, Types::Strict::String
|
|
48
|
+
attribute :timestamp, Types::Strict::String
|
|
49
|
+
attribute :worker_id, Types::Strict::String
|
|
50
|
+
attribute :checks, Types::Strict::Hash.map(Types::Strict::String, HealthCheck)
|
|
51
|
+
attribute :system_info, WorkerSystemInfo
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# ==========================================================================
|
|
55
|
+
# Metrics Types
|
|
56
|
+
# ==========================================================================
|
|
57
|
+
|
|
58
|
+
# Event router statistics
|
|
59
|
+
class EventRouterStats < Dry::Struct
|
|
60
|
+
attribute :total_routed, Types::Strict::Integer
|
|
61
|
+
attribute :durable_routed, Types::Strict::Integer
|
|
62
|
+
attribute :fast_routed, Types::Strict::Integer
|
|
63
|
+
attribute :broadcast_routed, Types::Strict::Integer
|
|
64
|
+
attribute :fast_delivery_errors, Types::Strict::Integer
|
|
65
|
+
attribute :routing_errors, Types::Strict::Integer
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# In-process event bus statistics
|
|
69
|
+
class InProcessEventBusStats < Dry::Struct
|
|
70
|
+
attribute :total_events_dispatched, Types::Strict::Integer
|
|
71
|
+
attribute :rust_handler_dispatches, Types::Strict::Integer
|
|
72
|
+
attribute :ffi_channel_dispatches, Types::Strict::Integer
|
|
73
|
+
attribute :rust_handler_errors, Types::Strict::Integer
|
|
74
|
+
attribute :ffi_channel_drops, Types::Strict::Integer
|
|
75
|
+
attribute :rust_subscriber_patterns, Types::Strict::Integer
|
|
76
|
+
attribute :rust_handler_count, Types::Strict::Integer
|
|
77
|
+
attribute :ffi_subscriber_count, Types::Strict::Integer
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Domain event statistics
|
|
81
|
+
class DomainEventStats < Dry::Struct
|
|
82
|
+
attribute :router, EventRouterStats
|
|
83
|
+
attribute :in_process_bus, InProcessEventBusStats
|
|
84
|
+
attribute :captured_at, Types::Strict::String
|
|
85
|
+
attribute :worker_id, Types::Strict::String
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# ==========================================================================
|
|
89
|
+
# Template Types
|
|
90
|
+
# ==========================================================================
|
|
91
|
+
|
|
92
|
+
# Template cache statistics
|
|
93
|
+
class CacheStats < Dry::Struct
|
|
94
|
+
attribute :total_entries, Types::Strict::Integer
|
|
95
|
+
attribute :hits, Types::Strict::Integer
|
|
96
|
+
attribute :misses, Types::Strict::Integer
|
|
97
|
+
attribute :evictions, Types::Strict::Integer
|
|
98
|
+
attribute :last_maintenance, Types::Strict::String.optional
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Cache operation result
|
|
102
|
+
class CacheOperationResult < Dry::Struct
|
|
103
|
+
attribute :success, Types::Strict::Bool
|
|
104
|
+
attribute :message, Types::Strict::String
|
|
105
|
+
attribute :timestamp, Types::Strict::String
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Template validation result
|
|
109
|
+
class TemplateValidation < Dry::Struct
|
|
110
|
+
attribute :valid, Types::Strict::Bool
|
|
111
|
+
attribute :namespace, Types::Strict::String
|
|
112
|
+
attribute :name, Types::Strict::String
|
|
113
|
+
attribute :version, Types::Strict::String
|
|
114
|
+
attribute :handler_count, Types::Strict::Integer
|
|
115
|
+
attribute :issues, Types::Strict::Array.of(Types::Strict::String)
|
|
116
|
+
attribute :handler_metadata, Types::Strict::Hash.optional
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# ==========================================================================
|
|
120
|
+
# Config Types (TAS-150: whitelist-only safe config exposure)
|
|
121
|
+
# ==========================================================================
|
|
122
|
+
|
|
123
|
+
# Configuration metadata (non-sensitive system info)
|
|
124
|
+
class ConfigMetadata < Dry::Struct
|
|
125
|
+
attribute :timestamp, Types::Strict::String
|
|
126
|
+
attribute :environment, Types::Strict::String
|
|
127
|
+
attribute :version, Types::Strict::String
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Non-sensitive auth configuration summary
|
|
131
|
+
class SafeAuthConfig < Dry::Struct
|
|
132
|
+
attribute :enabled, Types::Strict::Bool
|
|
133
|
+
attribute :verification_method, Types::Strict::String
|
|
134
|
+
attribute :jwt_issuer, Types::Strict::String
|
|
135
|
+
attribute :jwt_audience, Types::Strict::String
|
|
136
|
+
attribute :api_key_header, Types::Strict::String
|
|
137
|
+
attribute :api_key_count, Types::Strict::Integer
|
|
138
|
+
attribute :strict_validation, Types::Strict::Bool
|
|
139
|
+
attribute :allowed_algorithms, Types::Strict::Array.of(Types::Strict::String)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Non-sensitive messaging configuration
|
|
143
|
+
class SafeMessagingConfig < Dry::Struct
|
|
144
|
+
attribute :backend, Types::Strict::String
|
|
145
|
+
attribute :queues, Types::Strict::Array.of(Types::Strict::String)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Worker configuration response (safe fields only)
|
|
149
|
+
class RuntimeConfig < Dry::Struct
|
|
150
|
+
attribute :metadata, ConfigMetadata
|
|
151
|
+
attribute :worker_id, Types::Strict::String
|
|
152
|
+
attribute :worker_type, Types::Strict::String
|
|
153
|
+
attribute :auth, SafeAuthConfig
|
|
154
|
+
attribute :messaging, SafeMessagingConfig
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|