Skip to main content

golem_rust/
lib.rs

1// Copyright 2024-2025 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;
19
20pub mod bindings {
21    use wit_bindgen::generate;
22
23    generate!({
24        path: "wit",
25        world: "golem-rust",
26        generate_all,
27        generate_unused_types: true,
28        pub_export_macro: true,
29        with: {
30            "golem:rpc/types@0.2.2": golem_wasm::golem_rpc_0_2_x::types,
31            "wasi:io/poll@0.2.3": wstd::wasi::io::poll,
32            "wasi:clocks/wall-clock@0.2.3": wstd::wasi::clocks::wall_clock,
33        }
34    });
35}
36
37#[cfg(feature = "export_load_snapshot")]
38pub mod load_snapshot {
39    use wit_bindgen::generate;
40
41    generate!({
42        path: "wit",
43        world: "golem-rust-load-snapshot",
44        generate_all,
45        generate_unused_types: true,
46        pub_export_macro: true,
47        with: {
48            "golem:rpc/types@0.2.2": golem_wasm::golem_rpc_0_2_x::types,
49            "wasi:io/poll@0.2.3": wstd::wasi::io::poll,
50            "wasi:clocks/wall-clock@0.2.3": wstd::wasi::clocks::wall_clock,
51
52            "golem:api/host@1.3.0": crate::bindings::golem::api::host,
53            "golem:api/oplog@1.3.0": crate::bindings::golem::api::oplog,
54            "golem:api/context@1.3.0": crate::bindings::golem::api::context,
55            "golem:durability/durability@1.3.0": crate::bindings::golem::durability::durability,
56            "golem:rdbms/mysql@0.0.2": crate::bindings::golem::rdbms::mysql,
57            "golem:rdbms/postgres@0.0.2": crate::bindings::golem::rdbms::postgres,
58            "golem:rdbms/types@0.0.2": crate::bindings::golem::rdbms::types,
59            "wasi:blobstore/blobstore": crate::bindings::wasi::blobstore::blobstore,
60            "wasi:blobstore/container": crate::bindings::wasi::blobstore::container,
61            "wasi:blobstore/types": crate::bindings::wasi::blobstore::types,
62            "wasi:keyvalue/eventual-batch@0.1.0": crate::bindings::wasi::keyvalue::eventual_batch,
63            "wasi:keyvalue/eventual@0.1.0": crate::bindings::wasi::keyvalue::eventual,
64            "wasi:keyvalue/types@0.1.0": crate::bindings::wasi::keyvalue::types,
65            "wasi:keyvalue/wasi-keyvalue-error@0.1.0": crate::bindings::wasi::keyvalue::wasi_keyvalue_error,
66            "wasi:logging/logging": crate::bindings::wasi::logging::logging,
67        }
68    });
69
70    pub use __export_golem_rust_load_snapshot_impl as export_load_snapshot;
71}
72
73#[cfg(feature = "export_save_snapshot")]
74pub mod save_snapshot {
75    use wit_bindgen::generate;
76
77    generate!({
78        path: "wit",
79        world: "golem-rust-save-snapshot",
80        generate_all,
81        generate_unused_types: true,
82        pub_export_macro: true,
83        with: {
84            "golem:rpc/types@0.2.2": golem_wasm::golem_rpc_0_2_x::types,
85            "wasi:io/poll@0.2.3": wstd::wasi::io::poll,
86            "wasi:clocks/wall-clock@0.2.3": wstd::wasi::clocks::wall_clock,
87
88            "golem:api/host@1.3.0": crate::bindings::golem::api::host,
89            "golem:api/oplog@1.3.0": crate::bindings::golem::api::oplog,
90            "golem:api/context@1.3.0": crate::bindings::golem::api::context,
91            "golem:durability/durability@1.3.0": crate::bindings::golem::durability::durability,
92            "golem:rdbms/mysql@0.0.2": crate::bindings::golem::rdbms::mysql,
93            "golem:rdbms/postgres@0.0.2": crate::bindings::golem::rdbms::postgres,
94            "golem:rdbms/types@0.0.2": crate::bindings::golem::rdbms::types,
95            "wasi:blobstore/blobstore": crate::bindings::wasi::blobstore::blobstore,
96            "wasi:blobstore/container": crate::bindings::wasi::blobstore::container,
97            "wasi:blobstore/types": crate::bindings::wasi::blobstore::types,
98            "wasi:keyvalue/eventual-batch@0.1.0": crate::bindings::wasi::keyvalue::eventual_batch,
99            "wasi:keyvalue/eventual@0.1.0": crate::bindings::wasi::keyvalue::eventual,
100            "wasi:keyvalue/types@0.1.0": crate::bindings::wasi::keyvalue::types,
101            "wasi:keyvalue/wasi-keyvalue-error@0.1.0": crate::bindings::wasi::keyvalue::wasi_keyvalue_error,
102            "wasi:logging/logging": crate::bindings::wasi::logging::logging,
103        }
104    });
105
106    pub use __export_golem_rust_save_snapshot_impl as export_save_snapshot;
107}
108
109#[cfg(feature = "export_golem_agentic")]
110pub mod golem_agentic {
111    use wit_bindgen::generate;
112
113    generate!({
114        path: "wit",
115        world: "golem-agentic",
116        generate_all,
117        generate_unused_types: true,
118        pub_export_macro: true,
119        with: {
120            "golem:rpc/types@0.2.2": golem_wasm::golem_rpc_0_2_x::types,
121            "wasi:io/poll@0.2.3": wstd::wasi::io::poll,
122            "wasi:clocks/wall-clock@0.2.3": wstd::wasi::clocks::wall_clock,
123
124            "golem:api/host@1.3.0": crate::bindings::golem::api::host,
125            "golem:api/oplog@1.3.0": crate::bindings::golem::api::oplog,
126            "golem:api/context@1.3.0": crate::bindings::golem::api::context,
127            "golem:durability/durability@1.3.0": crate::bindings::golem::durability::durability,
128            "golem:rdbms/mysql@0.0.2": crate::bindings::golem::rdbms::mysql,
129            "golem:rdbms/postgres@0.0.2": crate::bindings::golem::rdbms::postgres,
130            "golem:rdbms/types@0.0.2": crate::bindings::golem::rdbms::types,
131            "wasi:blobstore/blobstore": crate::bindings::wasi::blobstore::blobstore,
132            "wasi:blobstore/container": crate::bindings::wasi::blobstore::container,
133            "wasi:blobstore/types": crate::bindings::wasi::blobstore::types,
134            "wasi:keyvalue/eventual-batch@0.1.0": crate::bindings::wasi::keyvalue::eventual_batch,
135            "wasi:keyvalue/eventual@0.1.0": crate::bindings::wasi::keyvalue::eventual,
136            "wasi:keyvalue/types@0.1.0": crate::bindings::wasi::keyvalue::types,
137            "wasi:keyvalue/wasi-keyvalue-error@0.1.0": crate::bindings::wasi::keyvalue::wasi_keyvalue_error,
138            "wasi:logging/logging": crate::bindings::wasi::logging::logging,
139        }
140    });
141
142    pub use __export_golem_agentic_impl as export_golem_agentic;
143}
144
145#[cfg(feature = "golem_ai")]
146pub mod golem_ai {
147    use wit_bindgen::generate;
148    generate!({
149        path: "wit",
150        world: "golem-ai",
151        generate_all,
152        generate_unused_types: true,
153        additional_derives: [crate::Schema],
154        pub_export_macro: true,
155        with: {
156            "golem:rpc/types@0.2.2": golem_wasm::golem_rpc_0_2_x::types,
157            "wasi:io/poll@0.2.3": wstd::wasi::io::poll,
158            "wasi:io/error@0.2.3": wstd::wasi::io::error,
159            "wasi:clocks/wall-clock@0.2.3": wstd::wasi::clocks::wall_clock,
160
161            "golem:api/host@1.3.0": crate::bindings::golem::api::host,
162            "golem:api/oplog@1.3.0": crate::bindings::golem::api::oplog,
163            "golem:api/context@1.3.0": crate::bindings::golem::api::context,
164            "golem:durability/durability@1.3.0": crate::bindings::golem::durability::durability,
165            "golem:rdbms/mysql@0.0.2": crate::bindings::golem::rdbms::mysql,
166            "golem:rdbms/postgres@0.0.2": crate::bindings::golem::rdbms::postgres,
167            "golem:rdbms/types@0.0.2": crate::bindings::golem::rdbms::types,
168            "wasi:blobstore/blobstore": crate::bindings::wasi::blobstore::blobstore,
169            "wasi:blobstore/container": crate::bindings::wasi::blobstore::container,
170            "wasi:blobstore/types": crate::bindings::wasi::blobstore::types,
171            "wasi:keyvalue/eventual-batch@0.1.0": crate::bindings::wasi::keyvalue::eventual_batch,
172            "wasi:keyvalue/eventual@0.1.0": crate::bindings::wasi::keyvalue::eventual,
173            "wasi:keyvalue/types@0.1.0": crate::bindings::wasi::keyvalue::types,
174            "wasi:keyvalue/wasi-keyvalue-error@0.1.0": crate::bindings::wasi::keyvalue::wasi_keyvalue_error,
175            "wasi:logging/logging": crate::bindings::wasi::logging::logging,
176        }
177    });
178}
179
180#[cfg(feature = "export_golem_agentic")]
181pub use ctor;
182
183#[cfg(feature = "export_golem_agentic")]
184pub use async_trait;
185
186#[cfg(feature = "export_oplog_processor")]
187pub mod oplog_processor {
188    use wit_bindgen::generate;
189
190    generate!({
191        path: "wit",
192        world: "golem-rust-oplog-processor",
193        generate_all,
194        generate_unused_types: true,
195        pub_export_macro: true,
196        with: {
197            "golem:rpc/types@0.2.2": golem_wasm::golem_rpc_0_2_x::types,
198            "wasi:io/poll@0.2.3": wstd::wasi::io::poll,
199            "wasi:clocks/wall-clock@0.2.3": wstd::wasi::clocks::wall_clock,
200
201            "golem:api/host@1.3.0": crate::bindings::golem::api::host,
202            "golem:api/oplog@1.3.0": crate::bindings::golem::api::oplog,
203            "golem:api/context@1.3.0": crate::bindings::golem::api::context,
204            "golem:durability/durability@1.3.0": crate::bindings::golem::durability::durability,
205            "golem:rdbms/mysql@0.0.2": crate::bindings::golem::rdbms::mysql,
206            "golem:rdbms/postgres@0.0.2": crate::bindings::golem::rdbms::postgres,
207            "golem:rdbms/types@0.0.2": crate::bindings::golem::rdbms::types,
208            "wasi:blobstore/blobstore": crate::bindings::wasi::blobstore::blobstore,
209            "wasi:blobstore/container": crate::bindings::wasi::blobstore::container,
210            "wasi:blobstore/types": crate::bindings::wasi::blobstore::types,
211            "wasi:keyvalue/eventual-batch@0.1.0": crate::bindings::wasi::keyvalue::eventual_batch,
212            "wasi:keyvalue/eventual@0.1.0": crate::bindings::wasi::keyvalue::eventual,
213            "wasi:keyvalue/types@0.1.0": crate::bindings::wasi::keyvalue::types,
214            "wasi:keyvalue/wasi-keyvalue-error@0.1.0": crate::bindings::wasi::keyvalue::wasi_keyvalue_error,
215            "wasi:logging/logging": crate::bindings::wasi::logging::logging,
216        }
217    });
218
219    pub use __export_golem_rust_oplog_processor_impl as export_oplog_processor;
220}
221
222#[cfg(feature = "export_golem_agentic")]
223pub mod agentic;
224
225#[cfg(feature = "durability")]
226pub mod durability;
227
228#[cfg(feature = "json")]
229mod json;
230
231#[cfg(feature = "json")]
232pub use json::*;
233
234mod transaction;
235pub mod value_and_type;
236
237use bindings::golem::api::host::*;
238
239pub use golem_wasm;
240
241pub use bindings::golem::api::host::{
242    complete_promise, create_promise, fork, get_promise, oplog_commit,
243};
244pub use bindings::golem::api::host::{ForkResult, PersistenceLevel, PromiseId};
245
246pub use transaction::*;
247
248#[cfg(feature = "macro")]
249pub use golem_rust_macro::*;
250
251/// Awaits a promise blocking the execution of the agent. The agent is going to be
252/// suspended until the promise is completed.
253///
254/// Use `await_promise` for an async version of this function, allowing to interleave
255/// awaiting of the promise with other operations.
256pub fn blocking_await_promise(promise_id: &PromiseId) -> Vec<u8> {
257    let promise = get_promise(promise_id);
258    let pollable = promise.subscribe();
259    pollable.block();
260    promise.get().unwrap()
261}
262
263/// Awaits a promise.
264///
265/// If only promises or timeouts are awaited simultaneously, the agent is going to be
266/// suspended until any of them completes.
267pub async fn await_promise(promise_id: &PromiseId) -> Vec<u8> {
268    let promise = get_promise(promise_id);
269    let pollable = promise.subscribe();
270    wstd::io::AsyncPollable::new(pollable).wait_for().await;
271    promise.get().unwrap()
272}
273
274#[derive(Clone, Debug, PartialEq)]
275pub struct RetryPolicy {
276    pub max_attempts: u32,
277    pub min_delay: std::time::Duration,
278    pub max_delay: std::time::Duration,
279    pub multiplier: f64,
280    pub max_jitter_factor: Option<f64>,
281}
282
283impl From<bindings::golem::api::host::RetryPolicy> for RetryPolicy {
284    fn from(value: bindings::golem::api::host::RetryPolicy) -> Self {
285        Self {
286            max_attempts: value.max_attempts,
287            min_delay: std::time::Duration::from_nanos(value.min_delay),
288            max_delay: std::time::Duration::from_nanos(value.max_delay),
289            multiplier: value.multiplier,
290            max_jitter_factor: value.max_jitter_factor,
291        }
292    }
293}
294
295impl From<RetryPolicy> for bindings::golem::api::host::RetryPolicy {
296    fn from(val: RetryPolicy) -> Self {
297        bindings::golem::api::host::RetryPolicy {
298            max_attempts: val.max_attempts,
299            min_delay: val.min_delay.as_nanos() as u64,
300            max_delay: val.max_delay.as_nanos() as u64,
301            multiplier: val.multiplier,
302            max_jitter_factor: val.max_jitter_factor,
303        }
304    }
305}
306
307pub struct PersistenceLevelGuard {
308    original_level: PersistenceLevel,
309}
310
311impl Drop for PersistenceLevelGuard {
312    fn drop(&mut self) {
313        set_oplog_persistence_level(self.original_level);
314    }
315}
316
317/// Temporarily sets the oplog persistence level to the given value.
318///
319/// When the returned guard is dropped, the original persistence level is restored.
320#[must_use]
321pub fn use_persistence_level(level: PersistenceLevel) -> PersistenceLevelGuard {
322    let original_level = get_oplog_persistence_level();
323    set_oplog_persistence_level(level);
324    PersistenceLevelGuard { original_level }
325}
326
327/// Executes the given function with the oplog persistence level set to the given value.
328pub fn with_persistence_level<R>(level: PersistenceLevel, f: impl FnOnce() -> R) -> R {
329    let _guard = use_persistence_level(level);
330    f()
331}
332
333pub struct IdempotenceModeGuard {
334    original: bool,
335}
336
337impl Drop for IdempotenceModeGuard {
338    fn drop(&mut self) {
339        set_idempotence_mode(self.original);
340    }
341}
342
343/// Temporarily sets the idempotence mode to the given value.
344///
345/// When the returned guard is dropped, the original idempotence mode is restored.
346#[must_use]
347pub fn use_idempotence_mode(mode: bool) -> IdempotenceModeGuard {
348    let original = get_idempotence_mode();
349    set_idempotence_mode(mode);
350    IdempotenceModeGuard { original }
351}
352
353/// Executes the given function with the idempotence mode set to the given value.
354pub fn with_idempotence_mode<R>(mode: bool, f: impl FnOnce() -> R) -> R {
355    let _guard = use_idempotence_mode(mode);
356    f()
357}
358
359/// Generates an idempotency key. This operation will never be replayed —
360/// 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)
361/// to introduce idempotence.
362pub fn generate_idempotency_key() -> uuid::Uuid {
363    Into::into(bindings::golem::api::host::generate_idempotency_key())
364}
365
366pub struct RetryPolicyGuard {
367    original: RetryPolicy,
368}
369
370impl Drop for RetryPolicyGuard {
371    fn drop(&mut self) {
372        set_retry_policy(Into::into(self.original.clone()));
373    }
374}
375
376/// Temporarily sets the retry policy to the given value.
377///
378/// When the returned guard is dropped, the original retry policy is restored.
379#[must_use]
380pub fn use_retry_policy(policy: RetryPolicy) -> RetryPolicyGuard {
381    let original = Into::into(get_retry_policy());
382    set_retry_policy(Into::into(policy));
383    RetryPolicyGuard { original }
384}
385
386/// Executes the given function with the retry policy set to the given value.
387pub fn with_retry_policy<R>(policy: RetryPolicy, f: impl FnOnce() -> R) -> R {
388    let _guard = use_retry_policy(policy);
389    f()
390}
391
392pub struct AtomicOperationGuard {
393    begin: OplogIndex,
394}
395
396impl Drop for AtomicOperationGuard {
397    fn drop(&mut self) {
398        mark_end_operation(self.begin);
399    }
400}
401
402/// Marks a block as an atomic operation
403///
404/// When the returned guard is dropped, the operation gets committed.
405/// In case of a failure, the whole operation will be re-executed during retry.
406#[must_use]
407pub fn mark_atomic_operation() -> AtomicOperationGuard {
408    let begin = mark_begin_operation();
409    AtomicOperationGuard { begin }
410}
411
412/// Executes the given function as an atomic operation.
413///
414/// In case of a failure, the whole operation will be re-executed during retry.
415pub fn atomically<T>(f: impl FnOnce() -> T) -> T {
416    let _guard = mark_atomic_operation();
417    f()
418}