pub struct Windmill {
pub workspace: String,
pub token: String,
pub base_internal_url: String,
pub client_config: Configuration,
}Fields§
§workspace: String§token: String§base_internal_url: String§client_config: ConfigurationImplementations§
Source§impl Windmill
impl Windmill
Sourcepub fn default() -> Result<Self, SdkError>
pub fn default() -> Result<Self, SdkError>
Creates a new Windmill instance with default configuration.
Reads configuration from environment variables:
WM_TOKENfor authentication tokenWM_WORKSPACEfor workspace nameBASE_INTERNAL_URLfor API base URL (appends/apiautomatically)
§Errors
Returns SdkError if:
- Required environment variables are missing
- Environment variables cannot be read
Sourcepub fn new(
token: Option<String>,
workspace: Option<String>,
base_internal_url: Option<String>,
) -> Result<Self, SdkError>
pub fn new( token: Option<String>, workspace: Option<String>, base_internal_url: Option<String>, ) -> Result<Self, SdkError>
Creates a new Windmill instance with optional overrides.
Falls back to environment variables for any None parameters:
WM_TOKENiftokenisNoneWM_WORKSPACEifworkspaceisNoneBASE_INTERNAL_URL+ “/api” ifbase_internal_urlisNone
§Parameters
token: Optional bearer token overrideworkspace: Optional workspace name overridebase_internal_url: Optional base URL override (without/apisuffix)
§Errors
Returns SdkError if:
- Required environment variables are missing when needed
- Environment variables cannot be read
Sourcepub fn get_variable<'a>(&'a self, path: &'a str) -> Result<Value, SdkError>
pub fn get_variable<'a>(&'a self, path: &'a str) -> Result<Value, SdkError>
Retrieves a variable from Windmill, automatically parsing it as JSON/YAML.
This is the convenience version that attempts to parse the variable value as:
- JSON (primary attempt)
- YAML (fallback if JSON parsing fails)
- Raw string (final fallback if both parsings fail)
For better performance when you know the format or don’t need parsing,
use Self::get_variable_raw instead.
§Arguments
path- Variable path (e.g., “u/user/variable_name”)
§Example
use wmill::Windmill;
use serde_json::json;
let wm = Windmill::default()?;
// For a variable containing JSON: {"key": "value"}
let json_var = wm.get_variable("u/admin/config")?;
// For a variable containing plain text
let text_var = wm.get_variable("u/user/plaintext_note")?;
See also: Self::get_variable_raw for the unparsed version
Sourcepub fn get_variable_raw<'a>(&'a self, path: &'a str) -> Result<String, SdkError>
pub fn get_variable_raw<'a>(&'a self, path: &'a str) -> Result<String, SdkError>
This is the faster version when:
- You know the variable contains plain text
- You want to handle parsing yourself
- You need maximum performance
Performance benefit comes from avoiding:
- JSON parsing attempt
- YAML parsing fallback
§Arguments
path- Variable path (e.g., “u/user/variable_name”)
§Example
use wmill::Windmill;
use serde_json::{json, Value};
let wm = Windmill::default()?;
// When you need the raw content
let raw_content = wm.get_variable_raw("u/user/custom_format")?;
// When you know it's JSON and want to parse it differently
let json_value: Value = serde_json::from_str(
&wm.get_variable_raw("u/admin/config")?
)?;
See also: Self::get_variable for the auto-parsed version
Sourcepub fn set_variable<'a>(
&'a self,
value: String,
path: &'a str,
is_secret: bool,
) -> Result<(), SdkError>
pub fn set_variable<'a>( &'a self, value: String, path: &'a str, is_secret: bool, ) -> Result<(), SdkError>
Creates or updates a variable in the workspace.
This function provides atomic variable management that:
- Creates a new variable if it doesn’t exist
- Updates an existing variable if found
- Handles both regular and secret variables
§Parameters
value: The variable value to setpath: The variable path/identifieris_secret: Whether to store as a secret (encrypted) variable
§Errors
Returns SdkError if:
- Variable fetch fails for reasons other than “not found”
- Variable creation fails
- Variable update fails
- Underlying API calls fail
§Notes
- For new variables, defaults to empty description
- Updates only modify the value (preserving other metadata)
- Secret status can only be set during creation
Sourcepub fn get_resource<'a, T: DeserializeOwned>(
&'a self,
path: &'a str,
) -> Result<T, SdkError>
pub fn get_resource<'a, T: DeserializeOwned>( &'a self, path: &'a str, ) -> Result<T, SdkError>
Fetches and deserializes a resource into a concrete type.
This is the recommended way to access resources when you know the expected type.
For raw JSON access or dynamic typing, use Self::get_resource_any instead.
§Type Parameters
T- Any type implementingDeserializeOwned(most structs with#[derive(Deserialize)])
§Arguments
path- The resource path (e.g., “u/user/resource_name”)
§Example
use wmill::Windmill;
use serde_json::{json, Value};
use serde::Deserialize;
#[derive(Deserialize)]
struct DbConfig {
url: String,
pool_size: Option<u32>,
}
let wm = Windmill::default()?;
// Directly deserialize to your type
let config: DbConfig = wm.get_resource("u/admin/db_connection")?;See also: Self::get_resource_any for untyped version
Sourcepub fn get_resource_any<'a>(&'a self, path: &'a str) -> Result<Value, SdkError>
pub fn get_resource_any<'a>(&'a self, path: &'a str) -> Result<Value, SdkError>
Fetches a raw JSON Value from Windmill by path.
Use this when you need the raw JSON structure or don’t have a concrete type to deserialize into.
For typed deserialization, prefer Self::get_resource instead.
§Arguments
path- The resource path (e.g., “u/user/resource_name”)
§Example
use wmill::Windmill;
let wm = Windmill::default()?;
// When you need to inspect the raw structure first
let json = wm.get_resource_any("u/admin/db_connection")?;
println!("Url is: {}", json["url"]);
See also: Self::get_resource for typed version
Sourcepub fn set_resource<'a>(
&'a self,
value: Option<Value>,
path: &'a str,
resource_type: &'a str,
) -> Result<(), SdkError>
pub fn set_resource<'a>( &'a self, value: Option<Value>, path: &'a str, resource_type: &'a str, ) -> Result<(), SdkError>
Creates or updates a resource in Windmill.
This function sets a resource’s value at the specified path, creating it if it doesn’t exist or updating it if it does. The resource will be of the specified type.
§Arguments
value- The value to set for the resource. UseNoneto create an empty resource.path- The ownership path of the resource (e.g., “u/user/resource_name”). Defines permissions based on Windmill’s path prefix system.resource_type- The type of resource to create (e.g., “postgresql”, “smtp”). Must be a pre-existing resource type.
§Examples
use wmill::Windmill;
let wm = Windmill::default()?;
wm.set_resource(
Some(serde_json::json!({"host": "localhost", "port": 5432})),
"u/admin/database",
"postgresql"
)?;Sourcepub fn get_state<'a, T: DeserializeOwned>(&'a self) -> Result<T, SdkError>
pub fn get_state<'a, T: DeserializeOwned>(&'a self) -> Result<T, SdkError>
Retrieves and deserializes the current typed state value for a script’s execution context.
This is the typed version of Self::get_state_any, automatically deserializing the state
into the specified type T that implements serde::de::DeserializeOwned.
§Type Parameter
T- The type to deserialize into (must implementserde::de::DeserializeOwned)
§Examples
use wmill::Windmill;
use serde_json::{json, Value};
use serde::Deserialize;
#[derive(Deserialize)]
struct ScriptState {
counter: i32,
last_run: String,
}
let wm = Windmill::default()?;
// Get typed state
let state: ScriptState = wm.get_state()?;
println!("Counter: {}, Last run: {}", state.counter, state.last_run);
§Behavior Details
- Uses same state path resolution as
Self::get_state_any(WM_STATE_PATH_NEW→WM_STATE_PATHfallback) - Performs runtime type checking during deserialization
§When to Use vs Self::get_state_any
| Use Case | get_state<T> | get_state_any |
|---|---|---|
| Known state structure | ✅ Preferred | ⚠️ Requires manual parsing |
| Dynamic state | ❌ Won’t compile | ✅ Works |
| Type safety | ✅ Compile-time checks | ❌ Runtime checks only |
§Notes
- For complex types, derive
Deserializeusing Serde attributes - Prefer this over
Self::get_state_anywhen state schema is stable - State modifications should use corresponding
Self::set_statewith matching type
§See Also
Self::get_state_any- Untyped state accessSelf::set_state- For updating typed states- Windmill State Management
Sourcepub fn get_state_any<'a>(&'a self) -> Result<Value, SdkError>
pub fn get_state_any<'a>(&'a self) -> Result<Value, SdkError>
Retrieves the current state value for a script’s execution context.
States persist data between runs of the same script by the same trigger (schedule or user).
This is the untyped version that returns a generic Value.
§Examples
use wmill::Windmill;
use serde_json::Value;
use serde::Deserialize;
let wm = Windmill::default()?;
// Get state (returns serde_json::Value)
let state: Value = wm.get_state_any()?;
// Use with default if empty
let counter = state.as_i64().unwrap_or(0);§Behavior Details
- Automatically uses the script’s state path from
WM_STATE_PATH_NEW(falls back toWM_STATE_PATH) - Returns the full state object stored as a Windmill resource
- State resources are hidden from Workspace view but visible under Resources → States
§Typical Use Cases
- Maintaining counters between runs
- Storing last execution timestamps
- Keeping reference data (like previous API responses)
§Notes
- For typed state access, use
get_state<T>instead - States are isolated per script and trigger combination
- Maximum state size: 5MB (compressed)
§See Also
Self::set_state- For updating the state- Windmill State Management
Sourcepub fn set_state<'a>(&'a self, value: Option<Value>) -> Result<(), SdkError>
pub fn set_state<'a>(&'a self, value: Option<Value>) -> Result<(), SdkError>
Updates or clears the script’s persistent state.
§Arguments
value- New state value (Some(Value)) orNoneto clear state
§Examples
use wmill::Windmill;
use serde_json::json;
let wm = Windmill::default()?;
// Set state
wm.set_state(Some(json!({"count": 42})))?;
// Clear state
wm.set_state(None)?;See also: Self::get_state, Self::get_state_any
Sourcepub fn run_script_sync<'a>(
&'a self,
ident: &'a str,
ident_is_hash: bool,
args: Value,
scheduled_in_secs: Option<u32>,
timeout_secs: Option<u64>,
verbose: bool,
assert_result_is_not_none: bool,
) -> Result<Value, SdkError>
pub fn run_script_sync<'a>( &'a self, ident: &'a str, ident_is_hash: bool, args: Value, scheduled_in_secs: Option<u32>, timeout_secs: Option<u64>, verbose: bool, assert_result_is_not_none: bool, ) -> Result<Value, SdkError>
Executes a script synchronously and waits for its completion.
This is a blocking version of run_script_async that handles the entire script execution
lifecycle including job scheduling and result waiting.
§Parameters
ident: Script identifier (either path or hash)ident_is_hash: Whether the identifier is a hash (true) or path (false)args: JSON arguments to pass to the scriptscheduled_in_secs: Optional delay before execution (in seconds)timeout_secs: Maximum time to wait for job completion (in seconds)verbose: Whether to print execution detailsassert_result_is_not_none: Whether to fail if the result is None
§Errors
Returns SdkError if:
- Script fails to start
- Job times out
- Result assertion fails
- Underlying API calls fail
Sourcepub fn run_script_async<'a>(
&'a self,
ident: &'a str,
ident_is_hash: bool,
args: Value,
scheduled_in_secs: Option<u32>,
) -> Result<Uuid, SdkError>
pub fn run_script_async<'a>( &'a self, ident: &'a str, ident_is_hash: bool, args: Value, scheduled_in_secs: Option<u32>, ) -> Result<Uuid, SdkError>
Asynchronously executes a script in Windmill and returns its job UUID.
This function runs a script either by path or by hash, with optional:
- Parent job inheritance (when run within a flow)
- Scheduled execution delay
- Argument passing
§Arguments
ident- Script identifier (path or hash depending onident_is_hash)ident_is_hash- If true,identis treated as a script hash; if false, as a pathargs- JSON arguments to pass to the script (must be an object if using path)scheduled_in_secs- Optional delay (in seconds) before execution
§Examples
use wmill::Windmill;
use serde_json::json;
let wm = Windmill::default()?;
let job_id = wm.run_script_async(
"u/user/script_path",
false,
json!({"param1": "value1"}),
Some(10) // Run after 10 seconds
)?;
§Behavior Details
- Automatic Job Inheritance:
- Detects
WM_JOB_IDenv var → sets asparent_job - Detects
WM_ROOT_FLOW_JOB_IDenv var → sets asroot_job
- Detects
- Scheduled Execution:
- When
scheduled_in_secsis provided, setsscheduled_in_secsin args
- When
- Argument Handling:
- For path-based execution (
ident_is_hash=false), args must be a JSON object - For hash-based execution, args can be any valid JSON value
- For path-based execution (
§Errors
SdkError::BadValueif path-based execution receives non-object arguments- API errors from Windmill’s backend
Sourcepub fn wait_job<'a>(
&'a self,
job_id: &'a str,
timeout_secs: Option<u64>,
verbose: bool,
assert_result_is_not_none: bool,
) -> Result<Value, SdkError>
pub fn wait_job<'a>( &'a self, job_id: &'a str, timeout_secs: Option<u64>, verbose: bool, assert_result_is_not_none: bool, ) -> Result<Value, SdkError>
Waits for a job to complete and returns its result.
This function provides both synchronous and asynchronous interfaces for waiting on job completion, with timeout handling and result validation.
§Parameters
job_id: The ID of the job to wait fortimeout_secs: Maximum time to wait (in seconds) before cancelling the jobverbose: Whether to print progress informationassert_result_is_not_none: Whether to fail if the job returns no result
§Errors
Returns SdkError if:
- Job fails or times out
- Result assertion fails when
assert_result_is_not_noneis true - Underlying API calls fail
§Behavior
- Polls job status at 500ms intervals
- Cancels job if timeout is reached
- Validates success status and optional result presence
- Returns either the result or appropriate error
Sourcepub fn get_job_status<'a>(
&'a self,
job_id: &'a str,
) -> Result<JobStatus, SdkError>
pub fn get_job_status<'a>( &'a self, job_id: &'a str, ) -> Result<JobStatus, SdkError>
Retrieves the current status of a Windmill job by its UUID.
This function queries the Windmill backend to determine whether a job is:
- Waiting to be executed
- Currently running
- Already completed
§Arguments
job_id- The UUID of the job to check (format: “xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”)
§Job Lifecycle States
- Waiting: Job is queued but hasn’t started execution
- Running: Job is currently being executed
- Completed: Job has finished (successfully or with errors)
Sourcepub fn get_result<'a>(&'a self, job_id: &'a str) -> Result<Value, SdkError>
pub fn get_result<'a>(&'a self, job_id: &'a str) -> Result<Value, SdkError>
Retrieves the result of a completed job.
This provides both synchronous and asynchronous interfaces for fetching the final result of a successfully completed job.
§Parameters
job_id: The ID of the completed job to fetch results for
§Errors
Returns SdkError if:
- Job is not found
- Job failed to complete successfully
- Underlying API calls fail
- Result cannot be parsed
§Notes
- Only works for jobs that have already completed
- For pending/running jobs, use
wait_jobinstead - Does not handle timeouts or polling - assumes job is already complete
Sourcepub fn set_progress<'a>(
&'a self,
value: u32,
job_id: Option<String>,
) -> Result<(), SdkError>
pub fn set_progress<'a>( &'a self, value: u32, job_id: Option<String>, ) -> Result<(), SdkError>
Updates the progress percentage of a running Windmill job.
This function allows scripts to report their execution progress (0-100%) back to the Windmill UI. Progress updates are visible in both the jobs dashboard and flow visualizations.
§Arguments
value- Progress percentage (0-100)job_id- Optional job UUID. If None, uses current job’s ID fromWM_JOB_IDenvironment variable
§Examples
use wmill::Windmill;
let wm = Windmill::default()?;
// Report progress for current job
wm.set_progress(25, None)?;
§Behavior Details
- Automatically handles flow context by detecting parent job ID
- Progress updates are reflected in real-time in the Windmill UI
- Typical usage pattern:
ⓘ
for (i, item) in items.iter().enumerate() { process(item); let progress = ((i + 1) * 100 / items.len()) as i32; wmill.set_progress(progress, None).await?; }
§Notes
- Only affects jobs that are currently running
- Progress values outside 0-99 range are clamped by the server
- Progress cannot decrease
- For flows, updates the progress of both the step and parent flow
§See Also
- Flow Progress Tracking
Self::get_progress- For reading job progress
Sourcepub fn get_progress<'a>(
&'a self,
job_id: Option<String>,
) -> Result<u32, SdkError>
pub fn get_progress<'a>( &'a self, job_id: Option<String>, ) -> Result<u32, SdkError>
Retrieves the current progress percentage of a Windmill job.
This function queries the Windmill backend to get the execution progress (0-100%) of either a specific job or the current job context.
§Arguments
job_id- Optional job UUID. IfNone, uses current job’s ID fromWM_JOB_IDenv var
§See Also
- Flow Progress Tracking
Self::set_progress- For updating job progress
Sourcepub fn call_api<'a, T>(
&'a self,
callback: impl Future<Output = T> + Send + 'a,
) -> T
pub fn call_api<'a, T>( &'a self, callback: impl Future<Output = T> + Send + 'a, ) -> T
Executes an API call in either asynchronous or synchronous mode based on compilation context.
This function serves as a bridge between async and sync code, automatically adapting its behavior:
- With
asyncfeature: Returns a boxed future for later await - Without
asyncfeature: Blocks immediately using the global runtime
§Examples
§Async usage (with async feature)
use wmill::Windmill;
let wm = Windmill::default()?;
let user = wm.call_api(wmill::apis::admin_api::get_user(&wm.client_config, &wm.workspace, "Bob"))?;
println!("User details: {:?}", user);§Sync usage (without async feature)
use wmill::Windmill;
let wm = Windmill::new(Some("<TOKEN>".into()), Some("admins".into()), Some("http://localhost:5000/api".into()))?;
let user = wm.call_api(wmill::apis::admin_api::get_user(&wm.client_config, &wm.workspace, "Bob"));
println!("User details: {:?}", user);