use http::uri::InvalidUri;
use temporalio_common::{
data_converters::PayloadConversionError,
protos::temporal::api::{common::v1::Payload, failure::v1::Failure, query::v1::QueryRejected},
};
use tonic::Code;
#[derive(thiserror::Error, Debug)]
#[non_exhaustive]
pub enum ClientConnectError {
#[error("Invalid URI: {0:?}")]
InvalidUri(#[from] InvalidUri),
#[error("Invalid headers: {0}")]
InvalidHeaders(#[from] InvalidHeaderError),
#[error("Server connection error: {0:?}")]
TonicTransportError(#[from] tonic::transport::Error),
#[error("`get_system_info` call error after connection: {0:?}")]
SystemInfoCallError(tonic::Status),
#[error("DNS resolution error for '{host}': {source}")]
DnsResolutionError {
host: String,
#[source]
source: std::io::Error,
},
#[error("Invalid client configuration: {0}")]
InvalidConfig(String),
}
#[derive(thiserror::Error, Debug)]
#[non_exhaustive]
pub enum InvalidHeaderError {
#[error("Invalid binary header key '{key}': {source}")]
InvalidBinaryHeaderKey {
key: String,
source: tonic::metadata::errors::InvalidMetadataKey,
},
#[error("Invalid ASCII header key '{key}': {source}")]
InvalidAsciiHeaderKey {
key: String,
source: tonic::metadata::errors::InvalidMetadataKey,
},
#[error("Invalid ASCII header value for key '{key}': {source}")]
InvalidAsciiHeaderValue {
key: String,
value: String,
source: tonic::metadata::errors::InvalidMetadataValue,
},
}
#[derive(thiserror::Error, Debug)]
#[non_exhaustive]
pub enum WorkflowStartError {
#[error("Workflow already started with run ID: {run_id:?}")]
AlreadyStarted {
run_id: Option<String>,
#[source]
source: tonic::Status,
},
#[error("Failed to serialize workflow input: {0}")]
PayloadConversion(#[from] PayloadConversionError),
#[error("Server error: {0}")]
Rpc(#[from] tonic::Status),
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum WorkflowQueryError {
#[error("Workflow not found")]
NotFound(#[source] tonic::Status),
#[error("Query rejected: workflow status {:?}", .0.status)]
Rejected(QueryRejected),
#[error("Payload conversion error: {0}")]
PayloadConversion(#[from] PayloadConversionError),
#[error("Server error: {0}")]
Rpc(tonic::Status),
#[error(transparent)]
Other(#[from] Box<dyn std::error::Error + Send + Sync>),
}
impl WorkflowQueryError {
pub(crate) fn from_status(status: tonic::Status) -> Self {
if status.code() == Code::NotFound {
Self::NotFound(status)
} else {
Self::Rpc(status)
}
}
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum WorkflowUpdateError {
#[error("Workflow not found")]
NotFound(#[source] tonic::Status),
#[error("Update failed: {0:?}")]
Failed(Box<Failure>),
#[error("Payload conversion error: {0}")]
PayloadConversion(#[from] PayloadConversionError),
#[error("Server error: {0}")]
Rpc(tonic::Status),
#[error(transparent)]
Other(#[from] Box<dyn std::error::Error + Send + Sync>),
}
impl WorkflowUpdateError {
pub(crate) fn from_status(status: tonic::Status) -> Self {
if status.code() == Code::NotFound {
Self::NotFound(status)
} else {
Self::Rpc(status)
}
}
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum WorkflowGetResultError {
#[error("Workflow failed: {0:?}")]
Failed(Box<Failure>),
#[error("Workflow cancelled")]
Cancelled {
details: Vec<Payload>,
},
#[error("Workflow terminated")]
Terminated {
details: Vec<Payload>,
},
#[error("Workflow timed out")]
TimedOut,
#[error("Workflow continued as new")]
ContinuedAsNew,
#[error("Workflow not found")]
NotFound(#[source] tonic::Status),
#[error("Payload conversion error: {0}")]
PayloadConversion(#[from] PayloadConversionError),
#[error("Server error: {0}")]
Rpc(tonic::Status),
#[error(transparent)]
Other(#[from] Box<dyn std::error::Error + Send + Sync>),
}
impl From<WorkflowInteractionError> for WorkflowGetResultError {
fn from(err: WorkflowInteractionError) -> Self {
match err {
WorkflowInteractionError::NotFound(s) => Self::NotFound(s),
WorkflowInteractionError::PayloadConversion(e) => Self::PayloadConversion(e),
WorkflowInteractionError::Rpc(s) => Self::Rpc(s),
WorkflowInteractionError::Other(e) => Self::Other(e),
}
}
}
impl WorkflowGetResultError {
pub fn is_workflow_outcome(&self) -> bool {
matches!(
self,
Self::Failed(_)
| Self::Cancelled { .. }
| Self::Terminated { .. }
| Self::TimedOut
| Self::ContinuedAsNew
)
}
}
#[derive(thiserror::Error, Debug)]
#[non_exhaustive]
pub enum ClientError {
#[error("Server error: {0}")]
Rpc(#[from] tonic::Status),
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum WorkflowInteractionError {
#[error("Workflow not found")]
NotFound(#[source] tonic::Status),
#[error("Payload conversion error: {0}")]
PayloadConversion(#[from] PayloadConversionError),
#[error("Server error: {0}")]
Rpc(tonic::Status),
#[error(transparent)]
Other(#[from] Box<dyn std::error::Error + Send + Sync>),
}
impl WorkflowInteractionError {
pub(crate) fn from_status(status: tonic::Status) -> Self {
if status.code() == Code::NotFound {
Self::NotFound(status)
} else {
Self::Rpc(status)
}
}
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum AsyncActivityError {
#[error("Activity not found")]
NotFound(#[source] tonic::Status),
#[error("Server error: {0}")]
Rpc(#[from] tonic::Status),
}
impl AsyncActivityError {
pub(crate) fn from_status(status: tonic::Status) -> Self {
if status.code() == Code::NotFound {
Self::NotFound(status)
} else {
Self::Rpc(status)
}
}
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum ClientNewError {}