1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
// Copyright (C) 2025 SyncMyOrders Sp. z o.o.
// SPDX-License-Identifier: AGPL-3.0-or-later
//! Global SDK registry for the #[durable] macro.
//!
//! This module provides global SDK registration so the #[durable] macro
//! can access the SDK without explicit passing.
//!
//! # Cancellation Support
//!
//! The registry provides cooperative cancellation for long-running operations.
//! When a cancellation signal is detected, the global cancellation flag is set,
//! allowing operations to be interrupted.
//!
//! Use `with_cancellation()` to wrap operations with cancellation support:
//!
//! ```ignore
//! let result = with_cancellation(|| some_long_operation())?;
//! ```
use Mutex;
use ;
use OnceCell;
use ;
use crateRuntaraSdk;
/// Global storage for the SDK instance.
static SDK_INSTANCE: = new;
/// Global cancellation flag triggered when a cancel signal is received.
static INSTANCE_CANCELLED: AtomicBool = new;
/// Register an SDK instance globally for use by #[durable] functions.
///
/// This should be called once at application startup after creating and
/// connecting the SDK.
///
/// # Panics
///
/// Panics if called more than once.
///
/// # Example
///
/// ```ignore
/// use runtara_sdk::{RuntaraSdk, register_sdk};
///
/// fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let sdk = RuntaraSdk::from_env()?;
/// sdk.connect()?;
///
/// // Register globally for #[durable] functions
/// register_sdk(sdk);
///
/// // Now #[durable] functions will use this SDK
/// Ok(())
/// }
/// ```
/// Get a reference to the registered SDK.
///
/// # Panics
///
/// Panics if no SDK has been registered.
/// Try to get a reference to the registered SDK.
///
/// Returns `None` if no SDK has been registered.
/// Stop the background heartbeat task.
///
/// This is a no-op in the synchronous SDK (no background tasks).
/// Check if the instance has been cancelled.
///
/// Returns `true` if a cancellation signal has been received.
/// Execute a closure with cancellation support.
///
/// This checks the cancellation flag before and after executing the closure.
/// If the flag is set, returns an error.
///
/// # Arguments
///
/// * `result` - The result of an operation to check
///
/// # Returns
///
/// Returns `Ok(result)` if the operation completed and no cancellation,
/// or `Err("Operation cancelled")` if cancellation was triggered.
///
/// # Example
///
/// ```ignore
/// use runtara_sdk::with_cancellation;
///
/// fn process_item(item: &Item) -> Result<Output, String> {
/// let response = with_cancellation(http_client.get(item.url).send())?;
/// Ok(response)
/// }
/// ```
/// Check a result with cancellation support, using a custom error type.
///
/// Similar to `with_cancellation`, but allows the caller to provide a custom
/// error to return if cancelled.
///
/// # Arguments
///
/// * `result` - The result of an operation
/// * `cancel_error` - The error to return if cancelled
///
/// # Example
///
/// ```ignore
/// let result = with_cancellation_err(
/// http_request(),
/// MyError::Cancelled("HTTP request cancelled".into())
/// )?;
/// ```
/// Trigger cancellation programmatically.
///
/// This is useful for testing or when cancellation needs to be triggered
/// from within the workflow (e.g., on a timeout condition).
///
/// Note: This only affects the current instance's cancellation flag.
/// The cancellation signal is not propagated to runtara-core.
/// Acknowledge cancellation to runtara-core.
///
/// This should be called when the instance detects a cancel signal and is about
/// to exit. It sends a SignalAck to the core, which will update the instance
/// status to "cancelled" (rather than "failed").
///
/// This function is used by the `#[durable]` macro when cancellation is detected.
/// It triggers the local cancellation flag and sends the acknowledgment.
///
/// # Example
///
/// ```ignore
/// // Detected cancel signal in checkpoint response
/// if checkpoint_result.should_cancel() {
/// acknowledge_cancellation();
/// return Err("Instance cancelled".into());
/// }
/// ```
/// Acknowledge a pause signal to runtara-core.
///
/// This must be called when the workflow suspends due to a pause signal.
/// Without acknowledgment, the pause signal remains pending and will be
/// detected again on resume, causing the workflow to suspend immediately
/// in an infinite loop.
///
/// # Example
///
/// ```ignore
/// // Detected pause signal in checkpoint response
/// if checkpoint_result.should_pause() {
/// acknowledge_pause();
/// sdk.suspended()?;
/// return Ok(());
/// }
/// ```