Skip to content

feat(tdl): Add end-to-end TDL package execution flow (resolves #302): - #317

Merged
sitaowang1998 merged 12 commits into
y-scope:mainfrom
LinZhihao-723:tdl-package-manager
May 5, 2026
Merged

feat(tdl): Add end-to-end TDL package execution flow (resolves #302):#317
sitaowang1998 merged 12 commits into
y-scope:mainfrom
LinZhihao-723:tdl-package-manager

Conversation

@LinZhihao-723

@LinZhihao-723 LinZhihao-723 commented May 4, 2026

Copy link
Copy Markdown
Member
  • Add register_tdl_package macro for TDL package declaration.
  • Add spider-task-executor crate and TDL package manager for loading packages at runtime.
  • Add an example TDL package and add integration tests to execute tasks inside the package through the TDL package manager.

Description

This is the last PR to resolve #302.

This PR adds end-to-end TDL package execution flow:

Task registration

We add register_tdl_package macro in spider-tdl for TDL package declaration. The macro takes a package name and a list of tasks, and generates C-ABI symbols for accessing the underlying tasks. The TDL package compiles into a cdylib, while it is expected that these symbols are global to each package (so that register_tdl_package should be unique in a crate).

The package identifies TDL packages uniquely by the package name. The macro detects duplicate names at compile time.

spider-task-executor

This is a new crate for the executor implementation. As the initial commit to this crate, we introduce the TDL package manager that wraps the cdylib and exposes safe Rust APIs to execute the tasks. Read the in-file docstrings for details.

Example: complex

This PR introduces an example TDL package, complex, which contains complex number type declaration and vector operations, including add, sub, dot-product, and cross-product.

An integration test is added to test the example, using the TDL package manager to load the compiled library. By doing so, we have built an end-to-end flow for:

TDL task declaration -> TDL package creation -> TDL task execution inside the Spider task executor

Checklist

  • The PR satisfies the contribution guidelines.
  • This is a breaking change and that has been indicated in the PR title, OR this isn't a
    breaking change.
  • Necessary docs have been updated, OR no docs need to be updated.

Validation performed

  • Ensure all gh workflows pass.
  • Add unit tests to test the registration macro and task execution manager.
  • Add integration tests for the end-to-end task execution.

Summary by CodeRabbit

Release Notes

  • New Features

    • Task executor component for dynamic package loading and execution
    • Semantic version compatibility validation for task packages
    • Task registration system and runtime dispatch infrastructure
  • Tests

    • Integration tests covering task execution workflows and complex arithmetic operations

@LinZhihao-723
LinZhihao-723 requested review from a team and sitaowang1998 as code owners May 4, 2026 20:38
@coderabbitai

coderabbitai Bot commented May 4, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@LinZhihao-723 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 54 minutes and 47 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 33101ae3-e555-4ee4-96f0-12476e2ea988

📥 Commits

Reviewing files that changed from the base of the PR and between 66e4a80 and e4c1a8d.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • components/spider-tdl-derive/src/task_macro.rs
  • components/spider-tdl/Cargo.toml
  • components/spider-tdl/src/register.rs
  • components/spider-tdl/src/version.rs

Walkthrough

This PR implements the TDL (Task Definition Language) package framework, enabling users to write custom task functions in Rust, compile them as shared libraries, and load them at runtime via C-FFI. It introduces spider-task-executor for dynamic package loading, extends spider-tdl with versioning and registration infrastructure, provides a working example package (huntsman-complex), and includes comprehensive integration tests validating end-to-end task execution.

Changes

TDL Package Framework Implementation

Layer / File(s) Summary
Version & Error Types
components/spider-tdl/src/version.rs, components/spider-task-executor/src/error.rs
Version struct with compile-time semver parsing and compatibility checking; ExecutorError enum covering library load failures, ABI mismatches, duplicates, UTF-8 issues, task errors, and deserialization failures.
Wire-Format Helpers & Registration
components/spider-tdl/src/register.rs, components/spider-tdl/src/lib.rs
register_tdl_package! macro generating dispatch tables and C-FFI entry points (__spider_tdl_package_get_version, __spider_tdl_package_get_name, __spider_tdl_package_execute); const-time task name uniqueness validation and msgpack error serialization.
Task Executor Loader & Manager
components/spider-task-executor/src/lib.rs, components/spider-task-executor/src/manager.rs
TdlPackage wrapper for loaded cdylib with ABI handshake, version validation, and task execution; TdlPackageManager registry indexing packages by name with duplicate-load rejection.
Macro Visibility Alignment
components/spider-tdl-derive/src/task_macro.rs
Generated params struct visibility now matches the annotated task function visibility instead of always being private.
Example Package & Types
examples/huntsman/complex/types/src/lib.rs, examples/huntsman/complex/tasks/src/lib.rs
Complex and ComplexVec wire-compatible serde types; huntsman-complex cdylib implementing five vector arithmetic tasks (add, sub, dot_product, cross_product, always_fail) with validation and error handling.
Workspace & Build Configuration
Cargo.toml, examples/huntsman/complex/tasks/Cargo.toml, examples/huntsman/complex/types/Cargo.toml, taskfiles/test.yaml
Workspace members added for new crates; cdylib and library targets configured; test environment extended to build and reference the example package.
Integration Tests & Documentation
tests/huntsman/tdl-integration/Cargo.toml, tests/huntsman/tdl-integration/src/lib.rs, tests/huntsman/tdl-integration/tests/complex.rs
Ignored integration test suite verifying package loading, version compatibility, duplicate rejection, multi-task round-trip execution, and error propagation with exact numeric assertions and error message validation.

Sequence Diagram

sequenceDiagram
    participant Storage
    participant Executor as Task Executor
    participant Manager as Package Manager
    participant Loader as Dynamic Loader
    participant Package as TDL Package (cdylib)

    Storage->>Executor: task_name + context + inputs (bytes)
    Executor->>Manager: load_package(path)
    Manager->>Loader: dlopen(cdylib_path)
    Loader->>Package: __spider_tdl_package_get_version()
    Package-->>Loader: Version struct
    Loader-->>Manager: Validate version compatibility
    Loader->>Package: __spider_tdl_package_get_name()
    Package-->>Loader: Package name bytes
    Loader-->>Manager: Register package in HashMap
    Manager-->>Executor: Package loaded
    
    Executor->>Manager: get_package(name)
    Manager-->>Executor: TdlPackage ref
    
    Executor->>Package: __spider_tdl_package_execute(task_name, ctx_bytes, inputs_bytes)
    Package->>Package: Deserialize context + inputs
    Package->>Package: Dispatch to task handler
    Package->>Package: Execute task logic
    Package->>Package: Serialize output or error
    Package-->>Executor: TaskExecutionResult (output_bytes or error_bytes)
    
    Executor->>Executor: Deserialize output/error
    Executor-->>Storage: output_bytes or ExecutorError
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

This PR introduces foundational FFI infrastructure (Version, ExecutorError, registration macro), dynamic library loading with ABI validation (TdlPackageManager, TdlPackage), a complete working example with vector arithmetic operations, and extensive integration tests. The heterogeneity spans version semantics, error handling, macro-based code generation, C-FFI symbol resolution and calling conventions, serde round-trips, and test fixture setup. The logic density is moderate-to-high (ABI compatibility checking, const-time uniqueness validation, error payload serialization), and the changes span multiple distinct architectural layers requiring separate reasoning for each. Familiarity with semver, libloading, msgpack serde, C-FFI conventions, and Rust proc-macros is beneficial for thorough review.

Suggested reviewers

  • sitaowang1998
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding an end-to-end TDL package execution flow, which is directly reflected in the PR's comprehensive additions to the TDL ecosystem.
Linked Issues check ✅ Passed All major objectives from issue #302 are implemented: spider-tdl crate with registration macro, spider-task-executor for package loading and execution, spider-tdl-derive with #[task] macro enhancements, example TDL package, and comprehensive integration tests.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing issue #302: new crates, macros, types, example package, integration tests, and taskfile updates for testing. No unrelated modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
components/spider-tdl-derive/src/task_macro.rs (1)

158-162: ⚡ Quick win

Hide the generated params type from public docs.

Now that this struct can become pub, public tasks will expose __<task>_params as synthetic API surface. Adding #[doc(hidden)] keeps the privacy fix without advertising macro internals.

Proposed change
         #[allow(non_camel_case_types)]
+        #[doc(hidden)]
         #[derive(::serde::Deserialize)]
         `#vis` struct `#params_struct_name` {
             #(`#param_fields`,)*
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/spider-tdl-derive/src/task_macro.rs` around lines 158 - 162, The
generated params struct (the symbol represented by `#params_struct_name`, e.g. the
synthetic __<task>_params type) is being emitted without hiding it from public
docs; add the #[doc(hidden)] attribute to the struct declaration in
task_macro.rs (the block that creates "struct `#params_struct_name` {
#(`#param_fields`,)* }") so that when the struct is generated as `pub` it is
excluded from API documentation while preserving the privacy fix.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@components/spider-tdl/src/register.rs`:
- Around line 91-128: The extern "C" function __spider_tdl_package_execute must
not allow Rust panics to unwind across the C ABI; wrap the call to
handler.execute_raw (the place where user task code runs) in
std::panic::catch_unwind (use std::panic::AssertUnwindSafe if necessary) and
convert any panic into a serialized TdlError payload (e.g. a TdlError variant
like Panic or a generic DeserializationError) using serialize_error_payload,
then return it via $crate::ffi::TaskExecutionResult::from_error; keep the
existing branches for Ok(output_bytes) and Err(error_bytes) but add a panic
branch that serializes the panic information and returns it instead of letting
the panic propagate.

In `@taskfiles/test.yaml`:
- Line 217: SPIDER_TDL_PACKAGE_COMPLEX currently hardcodes a Linux .so suffix;
update its value to pick the correct Rust cdylib extension based on the go-task
{{OS}} template (e.g. use a template conditional on .OS: return ".dylib" when
.OS == "darwin" and ".so" for Unix/Linux, optionally ".dll" for Windows). Modify
the SPIDER_TDL_PACKAGE_COMPLEX assignment that uses {{.G_RUST_BUILD_DIR}} so it
appends the chosen extension via the conditional (refer to the
SPIDER_TDL_PACKAGE_COMPLEX key and G_RUST_BUILD_DIR symbol in the file).

---

Nitpick comments:
In `@components/spider-tdl-derive/src/task_macro.rs`:
- Around line 158-162: The generated params struct (the symbol represented by
`#params_struct_name`, e.g. the synthetic __<task>_params type) is being emitted
without hiding it from public docs; add the #[doc(hidden)] attribute to the
struct declaration in task_macro.rs (the block that creates "struct
`#params_struct_name` { #(`#param_fields`,)* }") so that when the struct is
generated as `pub` it is excluded from API documentation while preserving the
privacy fix.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 96a04a54-318b-4b4d-8fe3-719e9dafb5f1

📥 Commits

Reviewing files that changed from the base of the PR and between 45b16ee and 66e4a80.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (17)
  • Cargo.toml
  • components/spider-task-executor/Cargo.toml
  • components/spider-task-executor/src/error.rs
  • components/spider-task-executor/src/lib.rs
  • components/spider-task-executor/src/manager.rs
  • components/spider-tdl-derive/src/task_macro.rs
  • components/spider-tdl/src/lib.rs
  • components/spider-tdl/src/register.rs
  • components/spider-tdl/src/version.rs
  • examples/huntsman/complex/tasks/Cargo.toml
  • examples/huntsman/complex/tasks/src/lib.rs
  • examples/huntsman/complex/types/Cargo.toml
  • examples/huntsman/complex/types/src/lib.rs
  • taskfiles/test.yaml
  • tests/huntsman/tdl-integration/Cargo.toml
  • tests/huntsman/tdl-integration/src/lib.rs
  • tests/huntsman/tdl-integration/tests/complex.rs

Comment thread components/spider-tdl/src/register.rs
Comment thread taskfiles/test.yaml

@sitaowang1998 sitaowang1998 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The overall design look good to me. Just a few implementation details.

//! 2. A private params struct holding the non-context parameters, with
//! 2. A params struct holding the non-context parameters (sharing the function's visibility, so it
//! never leaks through the public `Task::Params` associated type), with
//! `#[derive(serde::Deserialize)]` so the runtime can rebuild it from wire bytes.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make the phrase inside the parentheses a separate sentence?

Comment thread components/spider-tdl/src/version.rs Outdated
/// * `s` is an empty string.
/// * `s` contains a non-ASCII-digit byte.
/// * The parsed value would overflow `u32`.
const fn const_parse_u32(s: &str) -> u32 {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you considered crates like const_str or konst instead of implementing our own? Same for the string compare function and even the list of string uniqueness check in register.rs.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, we can use const_str for comparison and number parsing. The uniqueness check can't be rewritten using any of these libraries.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(spider-tdl): Add TDL package framework for user-defined task execution

2 participants