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 +4 -4
- data/DEVELOPMENT.md +11 -11
- data/ext/tasker_core/Cargo.toml +9 -9
- data/ext/tasker_core/src/bootstrap.rs +1 -1
- data/lib/tasker_core/event_bridge.rb +73 -9
- data/lib/tasker_core/version.rb +1 -1
- metadata +6 -10
- data/ext/tasker_core/src/CLAUDE.md +0 -7
- data/lib/tasker_core/errors/CLAUDE.md +0 -7
- data/lib/tasker_core/worker/CLAUDE.md +0 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c64517e396343d773d80bbf3c16e3112b267f9fe80c9106db6173a6f11b5c5c1
|
|
4
|
+
data.tar.gz: f80efaa7a98180794f55115d1bb566d8145de6a2bd3c87df06345d4e888f2f65
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
521
|
+
cd crates/tasker-rb
|
|
522
522
|
bundle exec rake clean
|
|
523
523
|
bundle exec rake compile
|
|
524
524
|
|
data/ext/tasker_core/Cargo.toml
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "tasker-rb"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.7"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
description = "Ruby bindings for tasker-core: High-performance workflow orchestration"
|
|
6
|
-
readme = "
|
|
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.
|
|
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.
|
|
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 = "
|
|
70
|
-
tasker-worker = { path = "
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
-
#
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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
|
-
|
|
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]
|
data/lib/tasker_core/version.rb
CHANGED
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.
|
|
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
|
|
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/
|
|
296
|
-
changelog_uri: https://github.com/tasker-systems/tasker-core/blob/main/
|
|
297
|
-
documentation_uri: https://
|
|
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://
|
|
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
|