Skip to main content

golem_rust/
lib.rs

1// Copyright 2024-2026 Golem Cloud
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#[cfg(test)]
16test_r::enable!();
17
18pub use uuid::Uuid;
19pub use wasip2;
20pub use wstd;
21
22pub mod bindings {
23    use wit_bindgen::generate;
24
25    generate!({
26        path: "wit",
27        world: "golem-rust",
28        generate_all,
29        generate_unused_types: true,
30        pub_export_macro: true,
31        with: {
32            "golem:core/types@1.5.0": golem_wasm::golem_core_1_5_x::types,
33            "wasi:io/poll@0.2.3": wasip2::io::poll,
34            "wasi:clocks/wall-clock@0.2.3": wasip2::clocks::wall_clock,
35        }
36    });
37}
38
39#[cfg(feature = "export_load_snapshot")]
40pub mod load_snapshot {
41    use wit_bindgen::generate;
42
43    generate!({
44        path: "wit",
45        world: "golem-rust-load-snapshot",
46        generate_all,
47        generate_unused_types: true,
48        pub_export_macro: true,
49        with: {
50            "golem:core/types@1.5.0": golem_wasm::golem_core_1_5_x::types,
51            "wasi:io/poll@0.2.3": wasip2::io::poll,
52            "wasi:clocks/wall-clock@0.2.3": wasip2::clocks::wall_clock,
53
54            "golem:api/host@1.5.0": crate::bindings::golem::api::host,
55            "golem:api/retry@1.5.0": crate::bindings::golem::api::retry,
56            "golem:api/oplog@1.5.0": crate::bindings::golem::api::oplog,
57            "golem:api/context@1.5.0": crate::bindings::golem::api::context,
58            "golem:durability/durability@1.5.0": crate::bindings::golem::durability::durability,
59            "golem:quota/types@1.5.0": crate::bindings::golem::quota::types,
60            "golem:rdbms/mysql@1.5.0": crate::bindings::golem::rdbms::mysql,
61            "golem:rdbms/postgres@1.5.0": crate::bindings::golem::rdbms::postgres,
62            "golem:rdbms/types@1.5.0": crate::bindings::golem::rdbms::types,
63            "wasi:blobstore/blobstore": crate::bindings::wasi::blobstore::blobstore,
64            "wasi:blobstore/container": crate::bindings::wasi::blobstore::container,
65            "wasi:blobstore/types": crate::bindings::wasi::blobstore::types,
66            "wasi:keyvalue/eventual-batch@0.1.0": crate::bindings::wasi::keyvalue::eventual_batch,
67            "wasi:keyvalue/eventual@0.1.0": crate::bindings::wasi::keyvalue::eventual,
68            "wasi:keyvalue/types@0.1.0": crate::bindings::wasi::keyvalue::types,
69            "wasi:keyvalue/wasi-keyvalue-error@0.1.0": crate::bindings::wasi::keyvalue::wasi_keyvalue_error,
70            "wasi:logging/logging": crate::bindings::wasi::logging::logging,
71        }
72    });
73
74    pub use __export_golem_rust_load_snapshot_impl as export_load_snapshot;
75}
76
77#[cfg(feature = "export_save_snapshot")]
78pub mod save_snapshot {
79    use wit_bindgen::generate;
80
81    generate!({
82        path: "wit",
83        world: "golem-rust-save-snapshot",
84        generate_all,
85        generate_unused_types: true,
86        pub_export_macro: true,
87        with: {
88            "golem:core/types@1.5.0": golem_wasm::golem_core_1_5_x::types,
89            "wasi:io/poll@0.2.3": wasip2::io::poll,
90            "wasi:clocks/wall-clock@0.2.3": wasip2::clocks::wall_clock,
91
92            "golem:api/host@1.5.0": crate::bindings::golem::api::host,
93            "golem:api/retry@1.5.0": crate::bindings::golem::api::retry,
94            "golem:api/oplog@1.5.0": crate::bindings::golem::api::oplog,
95            "golem:api/context@1.5.0": crate::bindings::golem::api::context,
96            "golem:durability/durability@1.5.0": crate::bindings::golem::durability::durability,
97            "golem:quota/types@1.5.0": crate::bindings::golem::quota::types,
98            "golem:rdbms/mysql@1.5.0": crate::bindings::golem::rdbms::mysql,
99            "golem:rdbms/postgres@1.5.0": crate::bindings::golem::rdbms::postgres,
100            "golem:rdbms/types@1.5.0": crate::bindings::golem::rdbms::types,
101            "wasi:blobstore/blobstore": crate::bindings::wasi::blobstore::blobstore,
102            "wasi:blobstore/container": crate::bindings::wasi::blobstore::container,
103            "wasi:blobstore/types": crate::bindings::wasi::blobstore::types,
104            "wasi:keyvalue/eventual-batch@0.1.0": crate::bindings::wasi::keyvalue::eventual_batch,
105            "wasi:keyvalue/eventual@0.1.0": crate::bindings::wasi::keyvalue::eventual,
106            "wasi:keyvalue/types@0.1.0": crate::bindings::wasi::keyvalue::types,
107            "wasi:keyvalue/wasi-keyvalue-error@0.1.0": crate::bindings::wasi::keyvalue::wasi_keyvalue_error,
108            "wasi:logging/logging": crate::bindings::wasi::logging::logging,
109        }
110    });
111
112    pub use __export_golem_rust_save_snapshot_impl as export_save_snapshot;
113}
114
115#[cfg(feature = "export_golem_agentic")]
116pub mod golem_agentic {
117    use wit_bindgen::generate;
118
119    generate!({
120        path: "wit",
121        world: "golem-agentic",
122        generate_all,
123        generate_unused_types: true,
124        pub_export_macro: true,
125
126        with: {
127            "golem:core/types@1.5.0": golem_wasm::golem_core_1_5_x::types,
128            "wasi:io/poll@0.2.3": wasip2::io::poll,
129            "wasi:clocks/wall-clock@0.2.3": wasip2::clocks::wall_clock,
130
131            "golem:api/host@1.5.0": crate::bindings::golem::api::host,
132            "golem:api/retry@1.5.0": crate::bindings::golem::api::retry,
133            "golem:api/oplog@1.5.0": crate::bindings::golem::api::oplog,
134            "golem:api/context@1.5.0": crate::bindings::golem::api::context,
135            "golem:durability/durability@1.5.0": crate::bindings::golem::durability::durability,
136            "golem:quota/types@1.5.0": crate::bindings::golem::quota::types,
137            "golem:rdbms/mysql@1.5.0": crate::bindings::golem::rdbms::mysql,
138            "golem:rdbms/postgres@1.5.0": crate::bindings::golem::rdbms::postgres,
139            "golem:rdbms/types@1.5.0": crate::bindings::golem::rdbms::types,
140            "wasi:blobstore/blobstore": crate::bindings::wasi::blobstore::blobstore,
141            "wasi:blobstore/container": crate::bindings::wasi::blobstore::container,
142            "wasi:blobstore/types": crate::bindings::wasi::blobstore::types,
143            "wasi:keyvalue/eventual-batch@0.1.0": crate::bindings::wasi::keyvalue::eventual_batch,
144            "wasi:keyvalue/eventual@0.1.0": crate::bindings::wasi::keyvalue::eventual,
145            "wasi:keyvalue/types@0.1.0": crate::bindings::wasi::keyvalue::types,
146            "wasi:keyvalue/wasi-keyvalue-error@0.1.0": crate::bindings::wasi::keyvalue::wasi_keyvalue_error,
147            "wasi:logging/logging": crate::bindings::wasi::logging::logging,
148        }
149    });
150
151    pub use __export_golem_agentic_impl as export_golem_agentic;
152}
153
154#[cfg(feature = "export_golem_agentic")]
155pub use ctor;
156
157#[cfg(feature = "export_golem_agentic")]
158pub use async_trait;
159
160#[cfg(feature = "export_golem_agentic")]
161pub use serde;
162
163#[cfg(feature = "export_golem_agentic")]
164pub use serde_json;
165
166#[cfg(feature = "export_oplog_processor")]
167pub mod oplog_processor {
168    use wit_bindgen::generate;
169
170    generate!({
171        path: "wit",
172        world: "golem-rust-oplog-processor",
173        generate_all,
174        generate_unused_types: true,
175        pub_export_macro: true,
176        with: {
177            "golem:core/types@1.5.0": golem_wasm::golem_core_1_5_x::types,
178            "wasi:io/poll@0.2.3": wasip2::io::poll,
179            "wasi:clocks/wall-clock@0.2.3": wasip2::clocks::wall_clock,
180
181            "golem:api/host@1.5.0": crate::bindings::golem::api::host,
182            "golem:api/retry@1.5.0": crate::bindings::golem::api::retry,
183            "golem:api/oplog@1.5.0": crate::bindings::golem::api::oplog,
184            "golem:api/context@1.5.0": crate::bindings::golem::api::context,
185            "golem:durability/durability@1.5.0": crate::bindings::golem::durability::durability,
186            "golem:quota/types@1.5.0": crate::bindings::golem::quota::types,
187            "golem:rdbms/mysql@1.5.0": crate::bindings::golem::rdbms::mysql,
188            "golem:rdbms/postgres@1.5.0": crate::bindings::golem::rdbms::postgres,
189            "golem:rdbms/types@1.5.0": crate::bindings::golem::rdbms::types,
190            "wasi:blobstore/blobstore": crate::bindings::wasi::blobstore::blobstore,
191            "wasi:blobstore/container": crate::bindings::wasi::blobstore::container,
192            "wasi:blobstore/types": crate::bindings::wasi::blobstore::types,
193            "wasi:keyvalue/eventual-batch@0.1.0": crate::bindings::wasi::keyvalue::eventual_batch,
194            "wasi:keyvalue/eventual@0.1.0": crate::bindings::wasi::keyvalue::eventual,
195            "wasi:keyvalue/types@0.1.0": crate::bindings::wasi::keyvalue::types,
196            "wasi:keyvalue/wasi-keyvalue-error@0.1.0": crate::bindings::wasi::keyvalue::wasi_keyvalue_error,
197            "wasi:logging/logging": crate::bindings::wasi::logging::logging,
198        }
199    });
200
201    pub use __export_golem_rust_oplog_processor_impl as export_oplog_processor;
202}
203
204#[cfg(feature = "export_golem_agentic")]
205pub mod agentic;
206
207#[cfg(feature = "durability")]
208pub mod durability;
209
210#[cfg(feature = "json")]
211mod json;
212
213#[cfg(feature = "json")]
214pub use json::*;
215
216mod checkpoint;
217pub mod quota;
218mod transaction;
219pub mod value_and_type;
220
221use std::future::Future;
222
223use bindings::golem::api::host::*;
224
225pub use golem_wasm;
226
227pub use bindings::golem::api::host::{ForkResult, PersistenceLevel, PromiseId};
228pub use bindings::golem::api::host::{
229    complete_promise, create_promise, fork, get_promise, oplog_commit,
230};
231
232pub mod websocket;
233pub use checkpoint::*;
234pub use quota::*;
235pub use transaction::*;
236pub use websocket::{WebSocketCloseInfo, WebSocketError, WebSocketMessage, WebsocketConnection};
237
238#[cfg(feature = "macro")]
239pub use golem_rust_macro::*;
240
241/// Awaits a promise blocking the execution of the agent. The agent is going to be
242/// suspended until the promise is completed.
243///
244/// Use `await_promise` for an async version of this function, allowing to interleave
245/// awaiting of the promise with other operations.
246pub fn blocking_await_promise(promise_id: &PromiseId) -> Vec<u8> {
247    let promise = get_promise(promise_id);
248    let pollable = promise.subscribe();
249    pollable.block();
250    promise.get().unwrap()
251}
252
253/// Awaits a promise.
254///
255/// If only promises or timeouts are awaited simultaneously, the agent is going to be
256/// suspended until any of them completes.
257pub async fn await_promise(promise_id: &PromiseId) -> Vec<u8> {
258    let promise = get_promise(promise_id);
259    let pollable = promise.subscribe();
260    wstd::io::AsyncPollable::new(pollable).wait_for().await;
261    promise.get().unwrap()
262}
263
264pub mod retry {
265    use crate::bindings::golem::api::retry as retry_api;
266
267    pub use retry_api::{NamedRetryPolicy, PredicateValue, RetryPolicy, RetryPredicate};
268
269    /// Get all retry policies active for this agent.
270    pub fn get_retry_policies() -> Vec<NamedRetryPolicy> {
271        retry_api::get_retry_policies()
272    }
273
274    /// Get a specific retry policy by name.
275    pub fn get_retry_policy_by_name(name: &str) -> Option<NamedRetryPolicy> {
276        retry_api::get_retry_policy_by_name(name)
277    }
278
279    /// Resolve the matching retry policy for a given operation context.
280    /// Evaluates named policies in descending priority order; returns the
281    /// policy from the first rule whose predicate matches, or none.
282    pub fn resolve_retry_policy(
283        verb: &str,
284        noun_uri: &str,
285        properties: &[(String, PredicateValue)],
286    ) -> Option<RetryPolicy> {
287        let props: Vec<(String, PredicateValue)> = properties.to_vec();
288        retry_api::resolve_retry_policy(verb, noun_uri, &props)
289    }
290
291    /// Add or overwrite a named retry policy (persisted to oplog).
292    /// If a policy with the same name exists, it is replaced.
293    pub fn set_retry_policy(policy: &NamedRetryPolicy) {
294        retry_api::set_retry_policy(policy);
295    }
296
297    /// Remove a named retry policy by name (persisted to oplog).
298    pub fn remove_retry_policy(name: &str) {
299        retry_api::remove_retry_policy(name);
300    }
301
302    /// Guard that restores the previous state of a named retry policy on drop.
303    /// If the policy existed before, it is restored; if it was newly added, it is removed.
304    pub struct RetryPolicyGuard {
305        previous: Option<NamedRetryPolicy>,
306        name: String,
307    }
308
309    impl Drop for RetryPolicyGuard {
310        fn drop(&mut self) {
311            match self.previous.take() {
312                Some(original) => set_retry_policy(&original),
313                None => remove_retry_policy(&self.name),
314            }
315        }
316    }
317
318    /// Temporarily sets a named retry policy. When the returned guard is dropped,
319    /// the previous policy with the same name is restored (or removed if it didn't exist).
320    #[must_use]
321    pub fn use_retry_policy(policy: NamedRetryPolicy) -> RetryPolicyGuard {
322        let previous = get_retry_policy_by_name(&policy.name);
323        let name = policy.name.clone();
324        set_retry_policy(&policy);
325        RetryPolicyGuard { previous, name }
326    }
327
328    /// Executes the given function with a named retry policy temporarily set.
329    pub fn with_retry_policy<R>(policy: NamedRetryPolicy, f: impl FnOnce() -> R) -> R {
330        let _guard = use_retry_policy(policy);
331        f()
332    }
333
334    /// Executes the given async function with a named retry policy temporarily set.
335    pub async fn with_retry_policy_async<R, F: std::future::Future<Output = R>>(
336        policy: NamedRetryPolicy,
337        f: impl FnOnce() -> F,
338    ) -> R {
339        let _guard = use_retry_policy(policy);
340        f().await
341    }
342}
343
344pub struct PersistenceLevelGuard {
345    original_level: PersistenceLevel,
346}
347
348impl Drop for PersistenceLevelGuard {
349    fn drop(&mut self) {
350        set_oplog_persistence_level(self.original_level);
351    }
352}
353
354/// Temporarily sets the oplog persistence level to the given value.
355///
356/// When the returned guard is dropped, the original persistence level is restored.
357#[must_use]
358pub fn use_persistence_level(level: PersistenceLevel) -> PersistenceLevelGuard {
359    let original_level = get_oplog_persistence_level();
360    set_oplog_persistence_level(level);
361    PersistenceLevelGuard { original_level }
362}
363
364/// Executes the given function with the oplog persistence level set to the given value.
365pub fn with_persistence_level<R>(level: PersistenceLevel, f: impl FnOnce() -> R) -> R {
366    let _guard = use_persistence_level(level);
367    f()
368}
369
370/// Executes the given async function with the oplog persistence level set to the given value.
371pub async fn with_persistence_level_async<R, F: Future<Output = R>>(
372    level: PersistenceLevel,
373    f: impl FnOnce() -> F,
374) -> R {
375    let _guard = use_persistence_level(level);
376    f().await
377}
378
379pub struct IdempotenceModeGuard {
380    original: bool,
381}
382
383impl Drop for IdempotenceModeGuard {
384    fn drop(&mut self) {
385        set_idempotence_mode(self.original);
386    }
387}
388
389/// Temporarily sets the idempotence mode to the given value.
390///
391/// When the returned guard is dropped, the original idempotence mode is restored.
392#[must_use]
393pub fn use_idempotence_mode(mode: bool) -> IdempotenceModeGuard {
394    let original = get_idempotence_mode();
395    set_idempotence_mode(mode);
396    IdempotenceModeGuard { original }
397}
398
399/// Executes the given function with the idempotence mode set to the given value.
400pub fn with_idempotence_mode<R>(mode: bool, f: impl FnOnce() -> R) -> R {
401    let _guard = use_idempotence_mode(mode);
402    f()
403}
404
405/// Executes the given async function with the idempotence mode set to the given value.
406pub async fn with_idempotence_mode_async<R, F: Future<Output = R>>(
407    mode: bool,
408    f: impl FnOnce() -> F,
409) -> R {
410    let _guard = use_idempotence_mode(mode);
411    f().await
412}
413
414/// Generates an idempotency key. This operation will never be replayed —
415/// i.e. not only is this key generated, but it is persisted and committed, such that the key can be used in third-party systems (e.g. payment processing)
416/// to introduce idempotence.
417pub fn generate_idempotency_key() -> uuid::Uuid {
418    Into::into(bindings::golem::api::host::generate_idempotency_key())
419}
420
421pub struct AtomicOperationGuard {
422    begin: OplogIndex,
423}
424
425impl Drop for AtomicOperationGuard {
426    fn drop(&mut self) {
427        mark_end_operation(self.begin);
428    }
429}
430
431/// Marks a block as an atomic operation
432///
433/// When the returned guard is dropped, the operation gets committed.
434/// In case of a failure, the whole operation will be re-executed during retry.
435#[must_use]
436pub fn mark_atomic_operation() -> AtomicOperationGuard {
437    let begin = mark_begin_operation();
438    AtomicOperationGuard { begin }
439}
440
441/// Executes the given function as an atomic operation.
442///
443/// In case of a failure, the whole operation will be re-executed during retry.
444pub fn atomically<T>(f: impl FnOnce() -> T) -> T {
445    let _guard = mark_atomic_operation();
446    f()
447}
448
449/// Executes the given async function as an atomic operation.
450///
451/// In case of a failure, the whole operation will be re-executed during retry.
452pub async fn atomically_async<T, F: Future<Output = T>>(f: impl FnOnce() -> F) -> T {
453    let _guard = mark_atomic_operation();
454    f().await
455}