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 use bindings::golem::websocket::client::{
233    CloseInfo as WebSocketCloseInfo, Error as WebSocketError, Message as WebSocketMessage,
234    WebsocketConnection,
235};
236pub use checkpoint::*;
237pub use quota::*;
238pub use transaction::*;
239
240#[cfg(feature = "macro")]
241pub use golem_rust_macro::*;
242
243/// Awaits a promise blocking the execution of the agent. The agent is going to be
244/// suspended until the promise is completed.
245///
246/// Use `await_promise` for an async version of this function, allowing to interleave
247/// awaiting of the promise with other operations.
248pub fn blocking_await_promise(promise_id: &PromiseId) -> Vec<u8> {
249    let promise = get_promise(promise_id);
250    let pollable = promise.subscribe();
251    pollable.block();
252    promise.get().unwrap()
253}
254
255/// Awaits a promise.
256///
257/// If only promises or timeouts are awaited simultaneously, the agent is going to be
258/// suspended until any of them completes.
259pub async fn await_promise(promise_id: &PromiseId) -> Vec<u8> {
260    let promise = get_promise(promise_id);
261    let pollable = promise.subscribe();
262    wstd::io::AsyncPollable::new(pollable).wait_for().await;
263    promise.get().unwrap()
264}
265
266pub mod retry {
267    use crate::bindings::golem::api::retry as retry_api;
268
269    pub use retry_api::{NamedRetryPolicy, PredicateValue, RetryPolicy, RetryPredicate};
270
271    /// Get all retry policies active for this agent.
272    pub fn get_retry_policies() -> Vec<NamedRetryPolicy> {
273        retry_api::get_retry_policies()
274    }
275
276    /// Get a specific retry policy by name.
277    pub fn get_retry_policy_by_name(name: &str) -> Option<NamedRetryPolicy> {
278        retry_api::get_retry_policy_by_name(name)
279    }
280
281    /// Resolve the matching retry policy for a given operation context.
282    /// Evaluates named policies in descending priority order; returns the
283    /// policy from the first rule whose predicate matches, or none.
284    pub fn resolve_retry_policy(
285        verb: &str,
286        noun_uri: &str,
287        properties: &[(String, PredicateValue)],
288    ) -> Option<RetryPolicy> {
289        let props: Vec<(String, PredicateValue)> = properties.to_vec();
290        retry_api::resolve_retry_policy(verb, noun_uri, &props)
291    }
292
293    /// Add or overwrite a named retry policy (persisted to oplog).
294    /// If a policy with the same name exists, it is replaced.
295    pub fn set_retry_policy(policy: &NamedRetryPolicy) {
296        retry_api::set_retry_policy(policy);
297    }
298
299    /// Remove a named retry policy by name (persisted to oplog).
300    pub fn remove_retry_policy(name: &str) {
301        retry_api::remove_retry_policy(name);
302    }
303
304    /// Guard that restores the previous state of a named retry policy on drop.
305    /// If the policy existed before, it is restored; if it was newly added, it is removed.
306    pub struct RetryPolicyGuard {
307        previous: Option<NamedRetryPolicy>,
308        name: String,
309    }
310
311    impl Drop for RetryPolicyGuard {
312        fn drop(&mut self) {
313            match self.previous.take() {
314                Some(original) => set_retry_policy(&original),
315                None => remove_retry_policy(&self.name),
316            }
317        }
318    }
319
320    /// Temporarily sets a named retry policy. When the returned guard is dropped,
321    /// the previous policy with the same name is restored (or removed if it didn't exist).
322    #[must_use]
323    pub fn use_retry_policy(policy: NamedRetryPolicy) -> RetryPolicyGuard {
324        let previous = get_retry_policy_by_name(&policy.name);
325        let name = policy.name.clone();
326        set_retry_policy(&policy);
327        RetryPolicyGuard { previous, name }
328    }
329
330    /// Executes the given function with a named retry policy temporarily set.
331    pub fn with_retry_policy<R>(policy: NamedRetryPolicy, f: impl FnOnce() -> R) -> R {
332        let _guard = use_retry_policy(policy);
333        f()
334    }
335
336    /// Executes the given async function with a named retry policy temporarily set.
337    pub async fn with_retry_policy_async<R, F: std::future::Future<Output = R>>(
338        policy: NamedRetryPolicy,
339        f: impl FnOnce() -> F,
340    ) -> R {
341        let _guard = use_retry_policy(policy);
342        f().await
343    }
344}
345
346pub struct PersistenceLevelGuard {
347    original_level: PersistenceLevel,
348}
349
350impl Drop for PersistenceLevelGuard {
351    fn drop(&mut self) {
352        set_oplog_persistence_level(self.original_level);
353    }
354}
355
356/// Temporarily sets the oplog persistence level to the given value.
357///
358/// When the returned guard is dropped, the original persistence level is restored.
359#[must_use]
360pub fn use_persistence_level(level: PersistenceLevel) -> PersistenceLevelGuard {
361    let original_level = get_oplog_persistence_level();
362    set_oplog_persistence_level(level);
363    PersistenceLevelGuard { original_level }
364}
365
366/// Executes the given function with the oplog persistence level set to the given value.
367pub fn with_persistence_level<R>(level: PersistenceLevel, f: impl FnOnce() -> R) -> R {
368    let _guard = use_persistence_level(level);
369    f()
370}
371
372/// Executes the given async function with the oplog persistence level set to the given value.
373pub async fn with_persistence_level_async<R, F: Future<Output = R>>(
374    level: PersistenceLevel,
375    f: impl FnOnce() -> F,
376) -> R {
377    let _guard = use_persistence_level(level);
378    f().await
379}
380
381pub struct IdempotenceModeGuard {
382    original: bool,
383}
384
385impl Drop for IdempotenceModeGuard {
386    fn drop(&mut self) {
387        set_idempotence_mode(self.original);
388    }
389}
390
391/// Temporarily sets the idempotence mode to the given value.
392///
393/// When the returned guard is dropped, the original idempotence mode is restored.
394#[must_use]
395pub fn use_idempotence_mode(mode: bool) -> IdempotenceModeGuard {
396    let original = get_idempotence_mode();
397    set_idempotence_mode(mode);
398    IdempotenceModeGuard { original }
399}
400
401/// Executes the given function with the idempotence mode set to the given value.
402pub fn with_idempotence_mode<R>(mode: bool, f: impl FnOnce() -> R) -> R {
403    let _guard = use_idempotence_mode(mode);
404    f()
405}
406
407/// Executes the given async function with the idempotence mode set to the given value.
408pub async fn with_idempotence_mode_async<R, F: Future<Output = R>>(
409    mode: bool,
410    f: impl FnOnce() -> F,
411) -> R {
412    let _guard = use_idempotence_mode(mode);
413    f().await
414}
415
416/// Generates an idempotency key. This operation will never be replayed —
417/// 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)
418/// to introduce idempotence.
419pub fn generate_idempotency_key() -> uuid::Uuid {
420    Into::into(bindings::golem::api::host::generate_idempotency_key())
421}
422
423pub struct AtomicOperationGuard {
424    begin: OplogIndex,
425}
426
427impl Drop for AtomicOperationGuard {
428    fn drop(&mut self) {
429        mark_end_operation(self.begin);
430    }
431}
432
433/// Marks a block as an atomic operation
434///
435/// When the returned guard is dropped, the operation gets committed.
436/// In case of a failure, the whole operation will be re-executed during retry.
437#[must_use]
438pub fn mark_atomic_operation() -> AtomicOperationGuard {
439    let begin = mark_begin_operation();
440    AtomicOperationGuard { begin }
441}
442
443/// Executes the given function as an atomic operation.
444///
445/// In case of a failure, the whole operation will be re-executed during retry.
446pub fn atomically<T>(f: impl FnOnce() -> T) -> T {
447    let _guard = mark_atomic_operation();
448    f()
449}
450
451/// Executes the given async function as an atomic operation.
452///
453/// In case of a failure, the whole operation will be re-executed during retry.
454pub async fn atomically_async<T, F: Future<Output = T>>(f: impl FnOnce() -> F) -> T {
455    let _guard = mark_atomic_operation();
456    f().await
457}