The user-facing surface for the durable DAG engine. A workflow run can now be
started three ways, all resolving the workflow by name in the caller's app
(`cx.app_id` / the resolved app — never a passed-in arg, the isolation
boundary), seeding a run the orchestrator advances.
SDK seam (shared):
- `WorkflowService` trait + `NoopWorkflowService` + `WorkflowError` in
`shared::workflow` (mirrors `InvokeService`); added to `Services` as a
noop-defaulted `with_workflow` builder (all `Services::new` call sites
unchanged).
- `WorkflowServiceImpl` (manager-core): resolves + seeds a run; authenticated
callers gated on `AppInvoke` (anonymous skips, script-as-gate), the same gate
`invoke()` uses.
- `executor-core::sdk::workflow` — the Rhai bridge `workflow::start(name, input)`
/ `workflow::start(name)`, registered in `register_all`. Returns the run id.
Admin API (manager-core `workflows_api`, mounted in the binary):
- `GET /apps/{app}/workflows` — definitions (AppRead)
- `POST /apps/{app}/workflows/{name}/runs` — start a run (AppInvoke)
- `GET /apps/{app}/workflows/{name}/runs` — run history (AppRead)
- `GET /apps/{app}/workflow-runs/{run_id}` — one run + its steps (AppRead)
`app_id` scopes every query; a foreign run 404s.
CLI (`pic workflows`): `ls` · `run <name> [--input JSON]` · `runs <name>` ·
`run-status <run_id>` — all `--app`-scoped; run definitions stay declarative
(`[[workflows]]` → `pic apply`).
Also: `list_runs_for_workflow` repo reader.
Tests: `workflow_service_start_seeds_a_run` (DB-gated — the SDK/API-shared
entry) + `workflow_run_executes_end_to_end` CLI journey (apply → `pic workflows
run` → poll `run-status` → succeeded, through the real binary + orchestrator).
fmt + clippy -D warnings clean, 449 manager-core lib tests, 14 orchestrator DB
tests, 18 executor-core lib tests, 3 workflow CLI journeys green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
73 lines
2.4 KiB
Rust
73 lines
2.4 KiB
Rust
//! SDK plumbing — types and the per-call registration entry point.
|
|
//!
|
|
//! `executor-core` is responsible for building the per-invocation Rhai
|
|
//! engine and wiring stateful services into it. v1.1.0 ships the
|
|
//! shapes (`Services` bundle, `SdkCallCx`, `register_all` entry point)
|
|
//! but no actual services — subsequent v1.1.x PRs (KV in v1.1.1,
|
|
//! docs in v1.1.2, …) extend `register_all` rather than re-threading
|
|
//! plumbing through `engine.rs`.
|
|
//!
|
|
//! Bridge functions (`json_to_dynamic` / `dynamic_to_json`) also live
|
|
//! here so service modules can convert values without `engine.rs`
|
|
//! being the only home for the conversion logic.
|
|
|
|
pub mod bridge;
|
|
pub mod cx;
|
|
pub mod dead_letters;
|
|
pub mod docs;
|
|
pub mod email;
|
|
pub mod files;
|
|
pub mod http;
|
|
pub mod invoke;
|
|
pub mod kv;
|
|
pub mod pubsub;
|
|
pub mod queue;
|
|
pub mod retry;
|
|
pub mod secrets;
|
|
pub mod stdlib;
|
|
pub mod users;
|
|
pub mod vars;
|
|
pub mod workflow;
|
|
|
|
pub use bridge::{dynamic_to_json, json_to_dynamic};
|
|
pub use cx::SdkCallCx;
|
|
|
|
use std::sync::Arc;
|
|
|
|
use picloud_shared::Services;
|
|
use rhai::Engine as RhaiEngine;
|
|
|
|
use crate::engine::Engine;
|
|
use crate::sandbox::Limits;
|
|
|
|
/// Single hook every v1.1.x stateful service registers into. Called
|
|
/// once per invocation, just after `build_engine` constructs the
|
|
/// sandboxed Rhai engine and just before script compilation.
|
|
///
|
|
/// v1.1.9 adds the `limits` + `self_engine` parameters needed by the
|
|
/// `invoke` bridge for synchronous re-entry. `self_engine` is `None`
|
|
/// in harnesses that didn't call `Engine::set_self_weak` after
|
|
/// construction; the invoke bridge surfaces a clear error in that case.
|
|
pub fn register_all(
|
|
engine: &mut RhaiEngine,
|
|
services: &Services,
|
|
cx: Arc<SdkCallCx>,
|
|
limits: Limits,
|
|
self_engine: Option<Arc<Engine>>,
|
|
) {
|
|
kv::register(engine, services, cx.clone());
|
|
docs::register(engine, services, cx.clone());
|
|
dead_letters::register(engine, services, cx.clone());
|
|
http::register(engine, services, cx.clone());
|
|
files::register(engine, services, cx.clone());
|
|
pubsub::register(engine, services, cx.clone());
|
|
queue::register(engine, services, cx.clone());
|
|
retry::register(engine, services, cx.clone());
|
|
secrets::register(engine, services, cx.clone());
|
|
vars::register(engine, services, cx.clone());
|
|
email::register(engine, services, cx.clone());
|
|
users::register(engine, services, cx.clone());
|
|
workflow::register(engine, services, cx.clone());
|
|
invoke::register(engine, services, cx, limits, self_engine);
|
|
}
|