fern/03-reference/baml_client/abort-signal.mdx
BAML provides cancellation support for in-flight function calls across all language clients. In TypeScript, this uses the modern AbortSignal API, while other languages use their native patterns.
| Language | Implementation | Import |
|---|---|---|
| TypeScript | AbortSignal API | Built-in (Node.js 15+) |
| Python | Custom AbortController | from baml_py import AbortController |
| Go | context.Context | Built-in |
| Rust | CancellationToken | use baml::CancellationToken |
| Ruby | Not supported | - |
// Manual cancellation
const controller = new AbortController()
const result = await b.FunctionName(input, {
signal: controller.signal
})
// Cancel operation
controller.abort()
// Automatic timeout using AbortSignal.timeout()
const result2 = await b.FunctionName(input, {
signal: AbortSignal.timeout(5000) // 5 second timeout
})
// Check if aborted
if (controller.signal.aborted) {
// Handle aborted state
}
signal: AbortSignal - Read-only signal that indicates if the controller has been abortedabort(reason?: any): void - Cancels the associated operation(s) with an optional reasonAbortSignal.timeout(delay: number): AbortSignal - Creates a signal that automatically aborts after the specified delay in millisecondsfrom baml_py import AbortController
# Create controller
controller = AbortController()
# or create a controller with a timeout
controller_with_timeout = AbortController(timeout_ms=5000)
# Pass to function call
result = await b.FunctionName(
input,
baml_options={"abort_controller": controller}
)
# Cancel operation
controller.abort()
# Check if aborted
if controller.aborted:
# Handle aborted state
aborted: bool - Returns True if the controller has been aborted__init__(timeout_ms: Optional[int] = None) - Constructs a controller with the defined timeout if provided. The timeout only starts once handed off to a BAML function.abort(reason: Any = None) -> None - Cancels the associated operation(s) with an optional reasonimport "context"
// Create cancellable context
ctx, cancel := context.WithCancel(context.Background())
// Pass context to function call
result, err := b.FunctionName(ctx, input)
// Cancel operation
cancel()
// Check if cancelled
select {
case <-ctx.Done():
// Context was cancelled
default:
// Still active
}
context.WithCancel(parent Context) (ctx Context, cancel CancelFunc) - Creates a cancellable contextcontext.WithTimeout(parent Context, timeout Duration) (Context, CancelFunc) - Creates a context with timeoutcontext.WithDeadline(parent Context, deadline Time) (Context, CancelFunc) - Creates a context with deadlineuse baml::CancellationToken;
use myproject::baml_client::sync_client::B;
use std::time::Duration;
// Create a token with timeout
let token = CancellationToken::new_with_timeout(Duration::from_secs(5));
let result = B.FunctionName
.with_cancellation_token(Some(token))
.call(input);
// Manual cancellation
let token = CancellationToken::new();
let token_clone = token.clone();
std::thread::spawn(move || {
std::thread::sleep(Duration::from_secs(5));
token_clone.cancel();
});
let result = B.FunctionName
.with_cancellation_token(Some(token))
.call(input);
CancellationToken::new() -> CancellationToken - Creates a new cancellation tokenCancellationToken::new_with_timeout(duration: Duration) -> CancellationToken - Creates a token that auto-cancels after the specified durationcancel() -> () - Cancels the associated operation(s)clone() -> CancellationToken - Clones the token for sharing across threadsAbortController is not currently supported in the Ruby client.
If you need cancellation support in Ruby, please contact us to discuss your use case.
</Tab> </Tabs>Abort controllers work seamlessly with streaming responses:
<Tabs> <Tab title="TypeScript" language="typescript"> ```typescript const controller = new AbortController() const stream = b.stream.FunctionName(input, { signal: controller.signal })try {
for await (const chunk of stream) {
// Process chunk
if (someCondition) {
controller.abort() // Stops the stream
break
}
}
} catch (error) {
if (error instanceof BamlAbortError) {
console.log('Stream was aborted:', error.reason)
}
}
```
async for chunk in stream:
# Process chunk
if some_condition:
controller.abort() # Stops the stream
break
```
stream := b.StreamFunctionName(ctx, input)
for chunk := range stream {
// Process chunk
if someCondition {
cancel() // Stops the stream
break
}
}
```
let token = CancellationToken::new();
let token_clone = token.clone();
let mut stream = B.FunctionName
.with_cancellation_token(Some(token))
.stream(input)
.unwrap();
for partial in stream.partials() {
// Process chunk
if some_condition {
token_clone.cancel(); // Stops the stream
break;
}
}
```
When an operation is aborted, language-specific errors are thrown:
BamlAbortErrorBamlAbortErrorcontext.Canceled or context.DeadlineExceededSee BamlAbortError for detailed error handling information.
// Manual timeout implementation
function withTimeout<T>(
operation: (signal: AbortSignal) => Promise<T>,
timeoutMs: number
): Promise<T> {
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), timeoutMs)
return operation(controller.signal).finally(() => {
clearTimeout(timeoutId)
})
}
// Usage
const result2 = await withTimeout(
(signal) => b.ExtractData(input, { signal }),
5000 // 5 second timeout
)
```
const operations = [
b.Operation1(input1, { signal: controller.signal }),
b.Operation2(input2, { signal: controller.signal }),
b.Operation3(input3, { signal: controller.signal })
]
// Cancel all if any fails
try {
const results = await Promise.all(operations)
} catch (error) {
controller.abort() // Cancel remaining operations
throw error
}
```
operations = [
b.Operation1(input1, baml_options={"abort_controller": controller}),
b.Operation2(input2, baml_options={"abort_controller": controller}),
b.Operation3(input3, baml_options={"abort_controller": controller})
]
# Cancel all if any fails
try:
results = await asyncio.gather(*operations)
except Exception as e:
controller.abort() # Cancel remaining operations
raise
```
errChan := make(chan error, 3)
// Start multiple concurrent operations
for i := 0; i < 3; i++ {
go func(idx int) {
_, err := b.Operation1(ctx, input)
errChan <- err
}(i)
}
// Cancel all operations after 100ms
time.Sleep(100 * time.Millisecond)
cancel()
```
// Shared token cancels all operations
let token = CancellationToken::new();
let input = input(); // Your input data
let handles: Vec<_> = (0..3).map(|_| {
let t = token.clone();
let input = input.clone();
thread::spawn(move || {
B.Operation1
.with_cancellation_token(Some(t))
.call(input)
})
}).collect();
// Cancel all after 100ms
thread::sleep(std::time::Duration::from_millis(100));
token.cancel();
```