tasker-rb 0.1.7-x86_64-linux → 0.1.8-x86_64-linux

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ef76abda3b0f0b478e4eaa31e4dfda4730971f67f32834bb94529af8139a7578
4
- data.tar.gz: 3b6abe2f8fe5560df69c4339b53cd2f7226b4bafcb9457e6a598bf594818e700
3
+ metadata.gz: 94ad33456f400b47ae52c1ed366515e8b689829a1242cf7e7552bf12f9851957
4
+ data.tar.gz: 8e88e9b23228defefdd04878dcfcbe23873ad3d40a986936d82388d827a6c7b0
5
5
  SHA512:
6
- metadata.gz: b818d34abcfcdbe664844373dc0a28efc48df10a29858553288d65371d2def98532d5e189b453c4582d173f0e1d169c996e16271ddfb8f1952b5592f2eedbfe8
7
- data.tar.gz: afec9ba13cf2f9e9957ab521baed47f865f12af391d4cc1a9545f295c7b45f93b296048614d8c22f37e8caaebfd5bfef977d4105a5d4b1a79e599e1a253c0bd8
6
+ metadata.gz: 10c1052fd139cb8207884b83c63f4dd891a37ad86017b7eaf087666d065bc70774787da888ae7eb8c7cdcb6ea55546e180eb181145618fb740a98d78c8b7e92b
7
+ data.tar.gz: 0e8e84861132fa0bc80631a65dc21ea5c075f8e5f86a229c80c162ad9b6ae68637b4fc0ba41aa503c0968d3365130571848373e972b60603099bf36a8ac89184
@@ -194,21 +194,54 @@ module TaskerCore
194
194
 
195
195
  # Send completion event back to Rust
196
196
  # Called by StepExecutionSubscriber after handler execution
197
+ #
198
+ # serde_magnus requires string keys for deserialization into Rust structs.
199
+ # Ruby hashes built with symbol literals (e.g. { success: true }) must be
200
+ # deep-stringified before crossing the FFI boundary.
201
+ #
202
+ # If the FFI call still fails (e.g. unexpected nil, type mismatch), the
203
+ # fallback path constructs a guaranteed-safe failure result so the step is
204
+ # marked as permanently failed rather than silently lost.
197
205
  def publish_step_completion(completion_data)
198
206
  return unless active?
199
207
 
200
- logger.debug "Sending step completion to Rust: #{completion_data[:event_id]}"
208
+ event_id_str = completion_data[:event_id].to_s
209
+ logger.debug "Sending step completion to Rust: #{event_id_str}"
201
210
 
202
211
  # Validate completion data
203
212
  validate_completion!(completion_data)
204
213
 
205
- # Send to Rust via FFI (TAS-67: complete_step_event takes event_id and completion_data)
206
- TaskerCore::FFI.complete_step_event(completion_data[:event_id].to_s, completion_data)
207
-
208
- # Also publish locally for monitoring/debugging
209
- publish('step.completion.sent', completion_data)
210
-
211
- logger.debug 'Step completion sent to Rust'
214
+ # serde_magnus expects string keys convert symbol keys at the FFI boundary
215
+ stringified = completion_data.deep_stringify_keys
216
+
217
+ begin
218
+ TaskerCore::FFI.complete_step_event(event_id_str, stringified)
219
+ # Only publish monitoring event after successful primary FFI
220
+ publish('step.completion.sent', completion_data)
221
+ logger.debug 'Step completion sent to Rust'
222
+ rescue StandardError => e
223
+ logger.error "FFI serialization failed for event #{event_id_str}: #{e.message}"
224
+ logger.error e.backtrace&.first(5)&.join("\n")
225
+
226
+ # Submit a minimal failure result that is guaranteed to deserialize
227
+ fallback = build_ffi_safe_failure(completion_data, e)
228
+ begin
229
+ TaskerCore::FFI.complete_step_event(event_id_str, fallback)
230
+ logger.warn "FFI fallback failure submitted for event #{event_id_str}"
231
+ begin
232
+ publish('step.completion.sent', fallback)
233
+ rescue StandardError => pub_err
234
+ logger.warn "Monitoring publish failed after fallback: #{pub_err.message}"
235
+ end
236
+ rescue StandardError => fallback_error
237
+ logger.error "FFI fallback also failed for event #{event_id_str}: " \
238
+ "#{fallback_error.message} (original error: #{e.message})"
239
+ raise fallback_error
240
+ end
241
+ end
242
+ rescue ArgumentError
243
+ # Validation errors from validate_completion! should propagate
244
+ raise
212
245
  rescue StandardError => e
213
246
  logger.error "Failed to send step completion: #{e.message}"
214
247
  logger.error e.backtrace.join("\n")
@@ -246,10 +279,13 @@ module TaskerCore
246
279
  # Validate checkpoint data
247
280
  validate_checkpoint_yield!(checkpoint_data)
248
281
 
282
+ # serde_magnus expects string keys — convert symbol keys at the FFI boundary
283
+ stringified = checkpoint_data.deep_stringify_keys
284
+
249
285
  # Send to Rust via FFI (TAS-125)
250
286
  success = TaskerCore::FFI.checkpoint_yield_step_event(
251
287
  checkpoint_data[:event_id].to_s,
252
- checkpoint_data
288
+ stringified
253
289
  )
254
290
 
255
291
  if success
@@ -311,6 +347,34 @@ module TaskerCore
311
347
  completion_data[:completed_at] ||= Time.now.utc.iso8601
312
348
  end
313
349
 
350
+ # Build a minimal StepExecutionResult-shaped hash that is guaranteed to
351
+ # deserialize through serde_magnus. Uses only string keys and primitive
352
+ # values so there is zero chance of a secondary serialization failure.
353
+ def build_ffi_safe_failure(original_data, error)
354
+ {
355
+ 'step_uuid' => original_data[:step_uuid].to_s,
356
+ 'task_uuid' => original_data[:task_uuid].to_s,
357
+ 'success' => false,
358
+ 'result' => {},
359
+ 'status' => 'error',
360
+ 'metadata' => {
361
+ 'execution_time_ms' => 0,
362
+ 'retryable' => false,
363
+ 'completed_at' => Time.now.utc.iso8601,
364
+ 'worker_id' => 'ruby_worker',
365
+ 'custom' => {
366
+ 'ffi_serialization_error' => error.message.to_s[0, 500],
367
+ 'original_success' => original_data[:success].to_s
368
+ }
369
+ },
370
+ 'error' => {
371
+ 'message' => "FFI serialization failed: #{error.message}"[0, 500],
372
+ 'error_type' => 'FFI_SERIALIZATION_ERROR',
373
+ 'retryable' => false
374
+ }
375
+ }
376
+ end
377
+
314
378
  # TAS-125: Validate checkpoint yield data before sending to Rust
315
379
  def validate_checkpoint_yield!(checkpoint_data)
316
380
  required_fields = %i[event_id step_uuid cursor items_processed]
Binary file
@@ -3,7 +3,7 @@
3
3
  module TaskerCore
4
4
  # Version synchronization with the core Rust crate
5
5
  # This should be kept in sync with the Cargo.toml version
6
- VERSION = '0.1.7'
6
+ VERSION = '0.1.8'
7
7
 
8
8
  def self.version_info
9
9
  {
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tasker-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.8
5
5
  platform: x86_64-linux
6
6
  authors:
7
7
  - Pete Taylor
@@ -187,7 +187,7 @@ description: |
187
187
  Ruby FFI bindings for tasker-core, providing 10-100x performance improvements
188
188
  for workflow orchestration, dependency resolution, and state management.
189
189
 
190
- This gem enables Rails applications using the Tasker engine to leverage
190
+ This gem enables Ruby applications using the Tasker engine to leverage
191
191
  Rust's performance for computationally intensive orchestration operations
192
192
  while maintaining Ruby's flexibility for business logic.
193
193
  email:
@@ -263,15 +263,14 @@ licenses:
263
263
  metadata:
264
264
  homepage_uri: https://github.com/tasker-systems/tasker-core
265
265
  source_code_uri: https://github.com/tasker-systems/tasker-core/tree/main/workers/ruby
266
- changelog_uri: https://github.com/tasker-systems/tasker-core/blob/main/workers/ruby/CHANGELOG.md
267
- documentation_uri: https://github.com/tasker-systems/tasker-core/blob/main/docs/RUBY.md
266
+ changelog_uri: https://github.com/tasker-systems/tasker-core/blob/main/CHANGELOG.md
267
+ documentation_uri: https://docs.tasker.systems
268
268
  bug_tracker_uri: https://github.com/tasker-systems/tasker-core/issues
269
269
  allowed_push_host: https://rubygems.org
270
270
  rubygems_mfa_required: 'true'
271
271
  post_install_message: "\n\U0001F980 tasker-rb successfully installed!\n\nThis gem
272
272
  provides high-performance Rust-powered workflow orchestration.\n\nDocumentation:
273
- https://github.com/tasker-systems/tasker-core/blob/main/docs/workers/ruby.md\n\nFor
274
- Rails integration, see the tasker-engine gem documentation.\n\n"
273
+ https://docs.tasker.systems\n\n"
275
274
  rdoc_options: []
276
275
  require_paths:
277
276
  - lib