tasker-rb 0.1.7 → 0.1.9

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: a8c5ed3385bea52ede9378bb4cd2f35c4fb03e285a0b811698fa34042b2a0c8a
4
- data.tar.gz: a9ce3c0d4d390ae8f0263ca60794c8a0997d99ca6272c52ccd7a8cea579de6ae
3
+ metadata.gz: c64517e396343d773d80bbf3c16e3112b267f9fe80c9106db6173a6f11b5c5c1
4
+ data.tar.gz: f80efaa7a98180794f55115d1bb566d8145de6a2bd3c87df06345d4e888f2f65
5
5
  SHA512:
6
- metadata.gz: d7957c47e7f5403a0adc3cbfc917b49196e44e21438276f806809662b0bd3abaa2ff14408e69233dd06e1521fece83cc0f320d3601d152e8ee69730212f3ca58
7
- data.tar.gz: e7844fe1ee414c7f3887db916b084c15ac44768885516792964bce9afff6cd807a8b847335428cb367fb7e0042730b8bc95a098e89cc7a24851ca0b96bc8b5db
6
+ metadata.gz: 4278e7281d156515822863927b49e5503d14f29aa29d817341bfa2466c7593fa430d1df90c740bb1cfae4dddf1135ada7618f3fd678fdb9d5ac3c03c80a40168
7
+ data.tar.gz: df8e4974bc9bdb55862aed084319e7082a21c0916217c250dc03ddbf33ed7705f73a3ae5d23ba09f7b77388c76b7445228c4e3731b9078a7cc059f3ab9b69a17
data/DEVELOPMENT.md CHANGED
@@ -11,7 +11,7 @@ cd /path/to/tasker-core
11
11
  docker compose -f docker/docker-compose.test.yml up --build -d
12
12
 
13
13
  # 2. Run Ruby tests
14
- cd workers/ruby
14
+ cd crates/tasker-rb
15
15
  bundle install
16
16
  bundle exec rspec --format documentation
17
17
 
@@ -27,7 +27,7 @@ cd /path/to/tasker-core
27
27
  docker compose -f docker/docker-compose.test.yml up postgres -d
28
28
 
29
29
  # 2. Setup Ruby environment
30
- cd workers/ruby
30
+ cd crates/tasker-rb
31
31
  bundle install
32
32
  bundle exec rake compile
33
33
 
@@ -36,7 +36,7 @@ cd ../..
36
36
  cargo build --all-features
37
37
 
38
38
  # 4. Run tests locally
39
- cd workers/ruby
39
+ cd crates/tasker-rb
40
40
  export DATABASE_URL="postgresql://tasker:tasker@localhost:5432/tasker_rust_test"
41
41
  bundle exec rspec --format documentation
42
42
  ```
@@ -53,7 +53,7 @@ export DATABASE_URL="postgresql://localhost/tasker_rust_test"
53
53
  cargo sqlx migrate run
54
54
 
55
55
  # 3. Setup Ruby
56
- cd workers/ruby
56
+ cd crates/tasker-rb
57
57
  bundle install
58
58
  bundle exec rake compile
59
59
 
@@ -70,7 +70,7 @@ bundle exec rake compile
70
70
 
71
71
  ### Ruby Dependencies
72
72
  ```bash
73
- cd workers/ruby
73
+ cd crates/tasker-rb
74
74
  bundle install
75
75
 
76
76
  # Key dependencies installed:
@@ -156,7 +156,7 @@ export MAGNUS_DEBUG="true"
156
156
 
157
157
  #### Unit Tests (Ruby)
158
158
  ```bash
159
- cd workers/ruby
159
+ cd crates/tasker-rb
160
160
 
161
161
  # Run all unit tests
162
162
  bundle exec rspec spec/ffi/ spec/types/ spec/worker/ --format documentation
@@ -172,7 +172,7 @@ bundle exec rspec spec/ffi/ spec/types/ spec/worker/ --format documentation --re
172
172
 
173
173
  #### Integration Tests (Docker-based)
174
174
  ```bash
175
- cd workers/ruby
175
+ cd crates/tasker-rb
176
176
 
177
177
  # Prerequisites: Start Docker services first
178
178
  docker compose -f ../../docker/docker-compose.test.yml up --build -d
@@ -261,7 +261,7 @@ cargo build --all-features --bin tasker-server
261
261
 
262
262
  ### 3. Start Ruby Worker Service
263
263
  ```bash
264
- cd workers/ruby
264
+ cd crates/tasker-rb
265
265
  export DATABASE_URL="postgresql://localhost/tasker_rust_dev"
266
266
  export TASKER_TEMPLATE_PATH="$(pwd)/spec/fixtures/templates"
267
267
  export RUBY_HANDLER_PATH="$(pwd)/spec/handlers/examples"
@@ -357,7 +357,7 @@ ruby -v
357
357
  gem list ffi
358
358
 
359
359
  # Clean and rebuild
360
- cd workers/ruby
360
+ cd crates/tasker-rb
361
361
  bundle exec rake clean
362
362
  bundle exec rake compile
363
363
 
@@ -443,7 +443,7 @@ bundle exec ruby benchmarks/workflow_performance_benchmark.rb
443
443
  ### Local CI Simulation
444
444
  ```bash
445
445
  # Run the same commands as CI
446
- cd workers/ruby
446
+ cd crates/tasker-rb
447
447
 
448
448
  # Install dependencies (like CI)
449
449
  bundle install
@@ -518,7 +518,7 @@ export RUBY_HANDLER_PATH="$(pwd)/spec/handlers/examples"
518
518
  #### "Ruby worker FFI bootstrap failed"
519
519
  ```bash
520
520
  # Solution: Check Ruby extension compilation
521
- cd workers/ruby
521
+ cd crates/tasker-rb
522
522
  bundle exec rake clean
523
523
  bundle exec rake compile
524
524
 
@@ -1,9 +1,9 @@
1
1
  [package]
2
2
  name = "tasker-rb"
3
- version = "0.1.5"
3
+ version = "0.1.7"
4
4
  edition = "2021"
5
5
  description = "Ruby bindings for tasker-core: High-performance workflow orchestration"
6
- readme = "../../../../README.md"
6
+ readme = "../../../README.md"
7
7
  repository = "https://github.com/tasker-systems/tasker-core"
8
8
  license = "MIT"
9
9
  keywords = ["bindings", "ffi", "magnus", "ruby", "worker"]
@@ -34,7 +34,7 @@ anyhow = "1.0"
34
34
  # Async trait support for FrameworkIntegration
35
35
  async-trait = "0.1"
36
36
  # Time handling for Ruby Time ↔ Rust DateTime conversion
37
- chrono = { version = "0.4.43", features = ["serde"] }
37
+ chrono = { version = "0.4.44", features = ["serde"] }
38
38
  # Environment variable loading
39
39
  dotenvy = "0.15"
40
40
  # Ruby FFI
@@ -49,7 +49,7 @@ once_cell = "1.19"
49
49
  serde = { version = "=1.0.228", features = ["derive", "std"] }
50
50
  # Serialization for Ruby ↔ Rust data conversion
51
51
  serde_json = "1.0"
52
- serde_magnus = "0.10"
52
+ serde_magnus = "0.11"
53
53
  serde_yaml = "0.9"
54
54
  # Database (needed for PgPool)
55
55
  sqlx = { version = "0.8", features = [
@@ -66,21 +66,21 @@ sqlx = { version = "0.8", features = [
66
66
  # Both path (for workspace builds) and version (for standalone/published builds).
67
67
  # cargo publish strips the path field, leaving only the version for crates.io resolution.
68
68
  # Version pins are updated by scripts/release/update-versions.sh during release-prepare.
69
- tasker-shared = { path = "../../../../tasker-shared", version = "=0.1.5" }
70
- tasker-worker = { path = "../../../../tasker-worker", version = "=0.1.5" }
69
+ tasker-shared = { path = "../../../tasker-shared", version = "=0.1.7" }
70
+ tasker-worker = { path = "../../../tasker-worker", version = "=0.1.7" }
71
71
  # Error handling
72
72
  thiserror = "2.0"
73
73
  # Async runtime for blocking on futures in FFI
74
- tokio = { version = "1.49", features = ["rt-multi-thread"] }
74
+ tokio = { version = "1.50", features = ["rt-multi-thread"] }
75
75
  # Logging
76
76
  tracing = "0.1"
77
77
  # UUID generation for event bridge
78
- uuid = { version = "1.11", features = ["serde", "v4", "v7"] }
78
+ uuid = { version = "1.22", features = ["serde", "v4", "v7"] }
79
79
  # Project root detection
80
80
  workspace_tools = { version = "0.11.0", features = ["full"] }
81
81
 
82
82
  [dev-dependencies]
83
- tasker-core = { package = "tasker-core", path = "../../../../", version = "=0.1.5" }
83
+ tasker-core = { package = "tasker-core", path = "../../../../", version = "=0.1.7" }
84
84
 
85
85
  [features]
86
86
  default = []
@@ -1,6 +1,6 @@
1
1
  //! # Ruby Worker Bootstrap
2
2
  //!
3
- //! TAS-67: Follows the same patterns as workers/rust/src/bootstrap.rs but adapted
3
+ //! TAS-67: Follows the same patterns as crates/tasker-example-rs/src/bootstrap.rs but adapted
4
4
  //! for Ruby FFI integration with magnus. Uses FfiDispatchChannel for step event
5
5
  //! dispatch instead of the legacy RubyEventHandler.
6
6
  //!
@@ -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]
@@ -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.9'
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.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pete Taylor
@@ -201,7 +201,7 @@ description: |
201
201
  Ruby FFI bindings for tasker-core, providing 10-100x performance improvements
202
202
  for workflow orchestration, dependency resolution, and state management.
203
203
 
204
- This gem enables Rails applications using the Tasker engine to leverage
204
+ This gem enables Ruby applications using the Tasker engine to leverage
205
205
  Rust's performance for computationally intensive orchestration operations
206
206
  while maintaining Ruby's flexibility for business logic.
207
207
  email:
@@ -216,7 +216,6 @@ files:
216
216
  - ext/tasker_core/Cargo.lock
217
217
  - ext/tasker_core/Cargo.toml
218
218
  - ext/tasker_core/extconf.rb
219
- - ext/tasker_core/src/CLAUDE.md
220
219
  - ext/tasker_core/src/bootstrap.rs
221
220
  - ext/tasker_core/src/bridge.rs
222
221
  - ext/tasker_core/src/client_ffi.rs
@@ -240,7 +239,6 @@ files:
240
239
  - lib/tasker_core/domain_events/publisher_registry.rb
241
240
  - lib/tasker_core/domain_events/subscriber_registry.rb
242
241
  - lib/tasker_core/errors.rb
243
- - lib/tasker_core/errors/CLAUDE.md
244
242
  - lib/tasker_core/errors/common.rb
245
243
  - lib/tasker_core/errors/error_classifier.rb
246
244
  - lib/tasker_core/event_bridge.rb
@@ -284,7 +282,6 @@ files:
284
282
  - lib/tasker_core/types/task_template.rb
285
283
  - lib/tasker_core/types/task_types.rb
286
284
  - lib/tasker_core/version.rb
287
- - lib/tasker_core/worker/CLAUDE.md
288
285
  - lib/tasker_core/worker/event_poller.rb
289
286
  - lib/tasker_core/worker/in_process_domain_event_poller.rb
290
287
  homepage: https://github.com/tasker-systems/tasker-core
@@ -292,16 +289,15 @@ licenses:
292
289
  - MIT
293
290
  metadata:
294
291
  homepage_uri: https://github.com/tasker-systems/tasker-core
295
- source_code_uri: https://github.com/tasker-systems/tasker-core/tree/main/workers/ruby
296
- changelog_uri: https://github.com/tasker-systems/tasker-core/blob/main/workers/ruby/CHANGELOG.md
297
- documentation_uri: https://github.com/tasker-systems/tasker-core/blob/main/docs/RUBY.md
292
+ source_code_uri: https://github.com/tasker-systems/tasker-core/tree/main/crates/tasker-rb
293
+ changelog_uri: https://github.com/tasker-systems/tasker-core/blob/main/CHANGELOG.md
294
+ documentation_uri: https://docs.tasker.systems
298
295
  bug_tracker_uri: https://github.com/tasker-systems/tasker-core/issues
299
296
  allowed_push_host: https://rubygems.org
300
297
  rubygems_mfa_required: 'true'
301
298
  post_install_message: "\n\U0001F980 tasker-rb successfully installed!\n\nThis gem
302
299
  provides high-performance Rust-powered workflow orchestration.\n\nDocumentation:
303
- https://github.com/tasker-systems/tasker-core/blob/main/docs/workers/ruby.md\n\nFor
304
- Rails integration, see the tasker-engine gem documentation.\n\n"
300
+ https://docs.tasker.systems\n\n"
305
301
  rdoc_options: []
306
302
  require_paths:
307
303
  - lib
@@ -1,7 +0,0 @@
1
- <claude-mem-context>
2
- # Recent Activity
3
-
4
- <!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
5
-
6
- *No recent activity*
7
- </claude-mem-context>
@@ -1,7 +0,0 @@
1
- <claude-mem-context>
2
- # Recent Activity
3
-
4
- <!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
5
-
6
- *No recent activity*
7
- </claude-mem-context>
@@ -1,7 +0,0 @@
1
- <claude-mem-context>
2
- # Recent Activity
3
-
4
- <!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
5
-
6
- *No recent activity*
7
- </claude-mem-context>