use std::time::Duration;
use temporalio_common::telemetry::TelemetryOptions;
use temporalio_sdk_core::{
CoreRuntime, PollerBehavior as CorePollerBehavior, RuntimeOptions as CoreRuntimeOptions,
TokioRuntimeBuilder as CoreTokioRuntimeBuilder, WorkflowErrorType as CoreWorkflowErrorType,
};
use crate::error::RuntimeError;
pub mod worker_tuner;
#[cfg(feature = "experimental")]
pub use temporalio_sdk_core::{Worker as CoreWorker, WorkerConfig};
#[derive(bon::Builder)]
#[builder(state_mod(vis = "pub"))]
#[non_exhaustive]
pub struct TokioRuntimeBuilder {
pub inner: tokio::runtime::Builder,
}
impl Default for TokioRuntimeBuilder {
fn default() -> Self {
Self {
inner: tokio::runtime::Builder::new_multi_thread(),
}
}
}
impl TokioRuntimeBuilder {
fn into_core(self) -> CoreTokioRuntimeBuilder<Box<dyn Fn() + Send + Sync>> {
CoreTokioRuntimeBuilder {
inner: self.inner,
lang_on_thread_start: None,
}
}
}
#[derive(bon::Builder, Clone, Copy, Debug, PartialEq)]
#[builder(state_mod(vis = "pub"))]
#[non_exhaustive]
pub struct AutoscalingOptions {
pub minimum: usize,
pub maximum: usize,
pub initial: usize,
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[non_exhaustive]
pub enum PollerBehavior {
SimpleMaximum(usize),
Autoscaling(AutoscalingOptions),
}
impl PollerBehavior {
pub(crate) fn into_core(self) -> CorePollerBehavior {
match self {
PollerBehavior::SimpleMaximum(maximum) => CorePollerBehavior::SimpleMaximum(maximum),
PollerBehavior::Autoscaling(AutoscalingOptions {
minimum,
maximum,
initial,
}) => CorePollerBehavior::Autoscaling {
minimum,
maximum,
initial,
},
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[non_exhaustive]
pub enum WorkflowErrorType {
Nondeterminism,
}
impl WorkflowErrorType {
pub(crate) fn into_core(self) -> CoreWorkflowErrorType {
match self {
WorkflowErrorType::Nondeterminism => CoreWorkflowErrorType::Nondeterminism,
}
}
}
#[derive(bon::Builder)]
#[builder(finish_fn(vis = "", name = build_internal))]
#[non_exhaustive]
pub struct RuntimeOptions {
#[builder(default)]
telemetry_options: TelemetryOptions,
#[builder(required, default = Some(Duration::from_secs(60)))]
heartbeat_interval: Option<Duration>,
#[builder(default)]
disable_environment_info: bool,
}
impl Default for RuntimeOptions {
fn default() -> Self {
Self::builder().build().expect("builder defaults are valid")
}
}
impl<S: runtime_options_builder::State> RuntimeOptionsBuilder<S> {
pub fn build(self) -> Result<RuntimeOptions, String> {
let options = self.build_internal();
if let Some(interval) = options.heartbeat_interval
&& (interval < Duration::from_secs(1) || interval > Duration::from_secs(60))
{
return Err(format!(
"heartbeat_interval ({interval:?}) must be between 1s and 60s",
));
}
Ok(options)
}
}
impl RuntimeOptions {
fn into_core(self) -> CoreRuntimeOptions {
CoreRuntimeOptions::builder()
.telemetry_options(self.telemetry_options)
.heartbeat_interval(self.heartbeat_interval)
.disable_environment_info(self.disable_environment_info)
.build()
.expect("SDK runtime options have already been validated")
}
}
pub struct Runtime(CoreRuntime);
impl Runtime {
pub fn new(
options: RuntimeOptions,
tokio_builder: TokioRuntimeBuilder,
) -> Result<Self, RuntimeError> {
CoreRuntime::new(options.into_core(), tokio_builder.into_core())
.map(Self)
.map_err(RuntimeError::from_core)
}
pub fn from_current_tokio(options: RuntimeOptions) -> Result<Self, RuntimeError> {
tokio::runtime::Handle::try_current().map_err(|_| RuntimeError::NoCurrentTokioRuntime)?;
CoreRuntime::new_assume_tokio(options.into_core())
.map(Self)
.map_err(RuntimeError::from_core)
}
#[deprecated(note = "use `Runtime::from_current_tokio` instead")]
pub fn new_assume_tokio(options: RuntimeOptions) -> Result<Self, RuntimeError> {
Self::from_current_tokio(options)
}
pub(crate) fn core(&self) -> &CoreRuntime {
&self.0
}
}
#[cfg(test)]
mod tests {
use super::{Runtime, TokioRuntimeBuilder};
use crate::error::RuntimeError;
#[test]
fn from_current_tokio_without_runtime_returns_error() {
assert!(matches!(
Runtime::from_current_tokio(Default::default()),
Err(RuntimeError::NoCurrentTokioRuntime)
));
}
#[test]
fn tokio_runtime_builder_constructs_with_an_inner_builder() {
let _builder = TokioRuntimeBuilder::builder()
.inner(tokio::runtime::Builder::new_current_thread())
.build();
}
}