Documentation Index Fetch the complete documentation index at: https://mintlify.com/slunghq/slung/llms.txt
Use this file to discover all available pages before exploring further.
Writeback functions let your workflow send data to external systems. Slung provides two writeback mechanisms: WebSocket for connected clients and HTTP for external APIs.
WebSocket Writeback
Send data to WebSocket clients connected to the Slung runtime.
Function
writeback_ws ( destination , "ALERT: threshold exceeded" ) ? ;
Function signature:
pub fn writeback_ws ( destination : u64 , data : & str ) -> Result <()>
Parameters:
destination: u64 - Producer connection ID
data: &str - Text data to send
Returns:
Ok(()) - Message sent successfully
Err(_) - Failed to send message
Host function:
unsafe extern "C" {
fn u_writeback_ws ( producer_ptr : u64 , data_ptr : usize ) -> u32 ;
}
Returns 0 on success, non-zero on failure.
Getting Producer IDs
Producer IDs come from the Event structure:
pub struct Event {
pub timestamp : i64 ,
pub value : f64 ,
pub tags : Vec < String >,
pub producers : Vec < u64 >, // WebSocket connection IDs
}
Example: Alert System
use slung :: prelude ::* ;
#[main]
fn main () -> Result <()> {
let handle = query_live ( "AVG:temp:[sensor=1]" ) ? ;
poll_handle ( handle , on_event , 100.0 ) ? ;
Ok (())
}
fn on_event ( event : Event , alert_threshold : f64 ) -> Result <()> {
if event . value > alert_threshold {
println! ( "event timestamp={} value={}" , event . timestamp, event . value);
for producer in event . producers {
writeback_ws ( producer , "ALERT: threshold exceeded" ) ? ;
}
}
Ok (())
}
Example: JSON Response
use slung :: prelude ::* ;
use serde_json :: json;
fn on_event ( event : Event , _ : ()) -> Result <()> {
let response = json! ({
"timestamp" : event . timestamp,
"value" : event . value,
"status" : if event . value > 100.0 { "high" } else { "normal" }
});
for producer in event . producers {
writeback_ws ( producer , & response . to_string ()) ? ;
}
Ok (())
}
Broadcasting to Multiple Clients
The producers field contains all connection IDs that contributed to the aggregate:
fn broadcast_alert ( event : Event , message : & str ) -> Result <()> {
println! ( "Broadcasting to {} clients" , event . producers . len ());
for producer in event . producers {
match writeback_ws ( producer , message ) {
Ok ( _ ) => println! ( "Sent to producer {}" , producer ),
Err ( e ) => println! ( "Failed to send to producer {}: {}" , producer , e ),
}
}
Ok (())
}
HTTP Writeback
Send HTTP requests to external APIs and receive responses.
Function
let response = writeback_http (
"https://api.example.com/alerts" ,
r#"{"level":"critical","value":105.3}"# ,
WritebackMethod :: POST
) ? ;
Function signature:
pub fn writeback_http (
destination : & str ,
data : & str ,
method : WritebackMethod
) -> Result < Option < Vec < u8 >>>
Parameters:
destination: &str - URL to send request to
data: &str - Request body
method: WritebackMethod - HTTP method
Returns:
Ok(Some(Vec<u8>)) - Response body as bytes
Ok(None) - No response body or request failed
Host function:
unsafe extern "C" {
fn u_writeback_http ( url_ptr : usize , data_ptr : usize , method_ptr : u32 ) -> usize ;
}
Returns a pointer to a response Region, or 0 when there’s no response body or the request fails.
HTTP Methods
pub enum WritebackMethod {
GET , // 0
POST , // 1
PUT , // 2
DELETE , // 3
}
Example: POST Alert
use slung :: prelude ::* ;
#[main]
fn main () -> Result <()> {
let handle = query_live ( "AVG:cpu:[host=prod]:[5min]" ) ? ;
poll_handle ( handle , on_event , 80.0 ) ? ;
Ok (())
}
fn on_event ( event : Event , threshold : f64 ) -> Result <()> {
if event . value > threshold {
let payload = format! (
r#"{{"timestamp":{},"value":{},"threshold":{}}}"# ,
event . timestamp, event . value, threshold
);
let response = writeback_http (
"https://api.example.com/alerts" ,
& payload ,
WritebackMethod :: POST
) ? ;
if let Some ( body ) = response {
println! ( "Alert sent, response: {:?}" , String :: from_utf8_lossy ( & body ));
} else {
println! ( "Alert sent, no response body" );
}
}
Ok (())
}
Example: GET External Data
use slung :: prelude ::* ;
fn fetch_config () -> Result < Option < String >> {
let response = writeback_http (
"https://api.example.com/config" ,
"" ,
WritebackMethod :: GET
) ? ;
match response {
Some ( body ) => Ok ( Some ( String :: from_utf8_lossy ( & body ) . to_string ())),
None => Ok ( None ),
}
}
Example: PUT Update
use slung :: prelude ::* ;
fn update_metric ( metric_id : & str , value : f64 ) -> Result <()> {
let url = format! ( "https://api.example.com/metrics/{}" , metric_id );
let payload = format! ( r#"{{"value":{}}}"# , value );
writeback_http ( & url , & payload , WritebackMethod :: PUT ) ? ;
Ok (())
}
Example: DELETE Resource
use slung :: prelude ::* ;
fn delete_stale_alert ( alert_id : & str ) -> Result <()> {
let url = format! ( "https://api.example.com/alerts/{}" , alert_id );
writeback_http ( & url , "" , WritebackMethod :: DELETE ) ? ;
Ok (())
}
Error Handling
WebSocket Errors
for producer in event . producers {
match writeback_ws ( producer , "message" ) {
Ok ( _ ) => {},
Err ( e ) => {
println! ( "Failed to send to producer {}: {}" , producer , e );
// Continue trying other producers
}
}
}
HTTP Errors
match writeback_http ( url , data , WritebackMethod :: POST ) ? {
Some ( body ) => {
// Got response
println! ( "Response: {:?}" , String :: from_utf8_lossy ( & body ));
}
None => {
// No response body or request failed
// Cannot distinguish between these cases
println! ( "Warning: no response (may indicate failure)" );
}
}
Advanced Patterns
Dual Writeback
Send to both WebSocket clients and HTTP endpoints:
fn on_event ( event : Event , threshold : f64 ) -> Result <()> {
if event . value > threshold {
let message = format! ( "Alert: value {} exceeds threshold {}" , event . value, threshold );
// Notify connected clients
for producer in & event . producers {
writeback_ws ( * producer , & message ) ? ;
}
// Log to external system
let payload = format! (
r#"{{"timestamp":{},"value":{},"producers":{}}}"# ,
event . timestamp, event . value, event . producers . len ()
);
writeback_http (
"https://api.example.com/logs" ,
& payload ,
WritebackMethod :: POST
) ? ;
}
Ok (())
}
Conditional Writeback
fn on_event ( event : Event , _ : ()) -> Result <()> {
match event . tags . iter () . find ( | t | t . starts_with ( "severity=" )) {
Some ( tag ) if tag . contains ( "critical" ) => {
// Critical: HTTP alert
writeback_http (
"https://pagerduty.example.com/alert" ,
& format! ( r#"{{"value":{}}}"# , event . value),
WritebackMethod :: POST
) ? ;
}
Some ( tag ) if tag . contains ( "warning" ) => {
// Warning: WebSocket notification
for producer in event . producers {
writeback_ws ( producer , "Warning level reached" ) ? ;
}
}
_ => {
// Info: no action
}
}
Ok (())
}
Rate Limiting
use std :: time :: { Duration , Instant };
static mut LAST_HTTP_CALL : Option < Instant > = None ;
const MIN_INTERVAL : Duration = Duration :: from_secs ( 60 );
fn rate_limited_writeback ( data : & str ) -> Result <()> {
unsafe {
let now = Instant :: now ();
if let Some ( last ) = LAST_HTTP_CALL {
if now . duration_since ( last ) < MIN_INTERVAL {
println! ( "Rate limit: skipping HTTP call" );
return Ok (());
}
}
writeback_http (
"https://api.example.com/metrics" ,
data ,
WritebackMethod :: POST
) ? ;
LAST_HTTP_CALL = Some ( now );
Ok (())
}
}
Best Practices
Handle failures gracefully : Writeback can fail if connections close or HTTP requests timeout
Don’t block on HTTP : HTTP writeback is synchronous and can slow your workflow
Batch when possible : Aggregate multiple events before writing back
Use appropriate protocols : WebSocket for real-time client notifications, HTTP for external integrations
Include context : Send enough information (timestamp, tags) for receivers to process events
Log failures : Track which producers or endpoints fail to help debug connectivity issues
Next Steps
Live Queries Learn about live query subscriptions
Historical Queries Query aggregated historical data