Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
ff13687
init
GregoryTravis Apr 8, 2026
566ab43
Remove demo cargo entry.
GregoryTravis Apr 8, 2026
691789a
Remove trivial accessor tests.
GregoryTravis Apr 8, 2026
fd77df6
Remove trivial accessor tests; fmt.
GregoryTravis Apr 8, 2026
d7e8f54
Remove unused methods.
GregoryTravis Apr 8, 2026
ff6f8a7
Integration test for startic summary and details.
GregoryTravis Apr 8, 2026
dfdafda
Use expect_legacy_query_matcher for confirming current details.
GregoryTravis Apr 8, 2026
d10c4f2
Build JSON via struct.
GregoryTravis Apr 9, 2026
22c32a0
Default values for infallible JSON encoding.
GregoryTravis Apr 9, 2026
28d46cb
Assert command list is empty.
GregoryTravis Apr 9, 2026
7127fa9
Remove unnecessary signal handler. Integration test for unset current…
GregoryTravis Apr 9, 2026
8b5dd66
Pin serde_json version in workspace.
GregoryTravis Apr 9, 2026
774e1a2
Remove unnecessary .to_string() calls
GregoryTravis Apr 9, 2026
010c875
Too much detail in comment.
GregoryTravis Apr 9, 2026
4f211ac
.expect() rather than .unwrap().
GregoryTravis Apr 9, 2026
f6dd302
Cleanup
GregoryTravis Apr 9, 2026
4f0af70
Cleanup
GregoryTravis Apr 9, 2026
e65f27a
Merge branch 'master' into gmt/rust-summary-and-details
GregoryTravis Apr 9, 2026
fd3235c
Remove duplicate serde_json entry
GregoryTravis Apr 9, 2026
36d3440
Don't use internal query name in public docstrings.
GregoryTravis Apr 9, 2026
c2b37db
fmt
GregoryTravis Apr 9, 2026
f6a4852
Docstrings for LegacyQueryResult.
GregoryTravis Apr 9, 2026
da87444
Use ctx.wait_condition in test workflows.
GregoryTravis Apr 10, 2026
bd2de01
Accessors through WorkflowExecutionDescription.
GregoryTravis Apr 10, 2026
bf88865
Update tests to expect JSON summaries.
GregoryTravis Apr 10, 2026
b7b8ae3
Merge branch 'master' into gmt/rust-summary-and-details
GregoryTravis Apr 10, 2026
6c59469
Merge branch 'master' into gmt/rust-summary-and-details
GregoryTravis Apr 10, 2026
a1f1e3b
Use default converter for query results.
GregoryTravis Apr 13, 2026
073310d
TOOD: Use DataConverter to avoid direct dependency on serde_json
GregoryTravis Apr 13, 2026
6618bb0
Remove current-details-demo entry
GregoryTravis Apr 13, 2026
d594dd2
Update test for plain serialization
GregoryTravis Apr 13, 2026
6602431
fmt
GregoryTravis Apr 13, 2026
50c0e2b
Update test for plain serialization
GregoryTravis Apr 13, 2026
2b35523
Remove serde_json dependency
GregoryTravis Apr 13, 2026
8586ccc
serde_json required for example linting
GregoryTravis Apr 13, 2026
921f5da
Or rather, under the examples feature
GregoryTravis Apr 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ prost = "0.14"
prost-types = { version = "0.7", package = "prost-wkt-types" }
pbjson = "0.9"
pbjson-build = "0.9"
serde_json = "1.0"

[workspace.lints.rust]
unreachable_pub = "warn"
Expand Down
1 change: 1 addition & 0 deletions crates/client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ tracing = "0.1"
url = "2.5"
uuid = { version = "1.18", features = ["v4"] }
rand = "0.10"
serde_json = { workspace = true }

[dependencies.temporalio-common]
path = "../common"
Expand Down
21 changes: 20 additions & 1 deletion crates/client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ use temporalio_common::{
HasWorkflowDefinition,
data_converters::{DataConverter, SerializationContextData},
protos::{
coresdk::IntoPayloadsExt,
coresdk::{AsJsonPayloadExt, IntoPayloadsExt},
grpc::health::v1::health_client::HealthClient,
proto_ts_to_system_time,
temporal::api::{
Expand All @@ -81,6 +81,7 @@ use temporalio_common::{
enums::v1::{TaskQueueKind, WorkflowExecutionStatus},
errordetails::v1::WorkflowExecutionAlreadyStartedFailure,
operatorservice::v1::operator_service_client::OperatorServiceClient,
sdk::v1::UserMetadata,
taskqueue::v1::TaskQueue,
testservice::v1::test_service_client::TestServiceClient,
workflow::v1 as workflow,
Expand Down Expand Up @@ -1030,6 +1031,22 @@ where
let workflow_id = options.workflow_id.clone();
let task_queue_name = options.task_queue.clone();

let user_metadata = if options.static_summary.is_some() || options.static_details.is_some()
Comment thread
GregoryTravis marked this conversation as resolved.
{
Some(UserMetadata {
summary: options.static_summary.map(|s| {
s.as_json_payload()
.expect("String-to-JSON payload serialization is infallible")
}),
details: options.static_details.map(|s| {
s.as_json_payload()
.expect("String-to-JSON payload serialization is infallible")
}),
})
Comment thread
GregoryTravis marked this conversation as resolved.
} else {
None
};

let run_id = if let Some(start_signal) = options.start_signal {
// Use signal-with-start when a start_signal is provided
let res = WorkflowService::signal_with_start_workflow_execution(
Expand Down Expand Up @@ -1060,6 +1077,7 @@ where
search_attributes: options.search_attributes.map(|d| d.into()),
cron_schedule: options.cron_schedule.unwrap_or_default(),
header: options.header.or(start_signal.header),
user_metadata,
..Default::default()
}
.into_request(),
Expand Down Expand Up @@ -1100,6 +1118,7 @@ where
completion_callbacks: options.completion_callbacks,
priority: Some(options.priority.into()),
header: options.header,
user_metadata,
..Default::default()
}
.into_request(),
Expand Down
6 changes: 6 additions & 0 deletions crates/client/src/options_structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,12 @@ pub struct WorkflowStartOptions {

/// Headers to include with the start request.
pub header: Option<Header>,

/// Single-line static summary for the workflow, shown in the Temporal UI.
pub static_summary: Option<String>,

/// Multi-line static details for the workflow, shown in the Temporal UI.
pub static_details: Option<String>,
}

/// A signal to send atomically when starting a workflow.
Expand Down
28 changes: 28 additions & 0 deletions crates/client/src/workflow_handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,34 @@ impl WorkflowExecutionDescription {
fn new(raw_description: DescribeWorkflowExecutionResponse) -> Self {
Self { raw_description }
}

/// The static summary set when the workflow was started, if any.
// TOOD: Use DataConverter to avoid direct dependency on serde_json
pub fn static_summary(&self) -> Option<String> {
let payload = self
.raw_description
.execution_config
.as_ref()?
.user_metadata
.as_ref()?
.summary
.as_ref()?;
serde_json::from_slice(&payload.data).ok()
}

/// The static details set when the workflow was started, if any.
// TOOD: Use DataConverter to avoid direct dependency on serde_json
pub fn static_details(&self) -> Option<String> {
let payload = self
.raw_description
.execution_config
.as_ref()?
.user_metadata
.as_ref()?
.details
.as_ref()?;
serde_json::from_slice(&payload.data).ok()
}
}

// TODO [rust-sdk-branch]: Could implment stream a-la ListWorkflowsStream
Expand Down
2 changes: 1 addition & 1 deletion crates/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ prost-types = { workspace = true }
rand = { version = "0.10", optional = true }
ringbuf = { version = "0.4", optional = true }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_json = { workspace = true }
thiserror = { workspace = true }
tokio = { version = "1.47", features = [], optional = true }
toml = { version = "1.0", optional = true }
Expand Down
1 change: 1 addition & 0 deletions crates/common/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
},
&[
"./protos/local/temporal/sdk/core/core_interface.proto",
"./protos/api_upstream/temporal/api/sdk/v1/workflow_metadata.proto",
"./protos/api_upstream/temporal/api/workflowservice/v1/service.proto",
"./protos/api_upstream/temporal/api/operatorservice/v1/service.proto",
"./protos/api_upstream/temporal/api/errordetails/v1/message.proto",
Expand Down
2 changes: 1 addition & 1 deletion crates/sdk-core-c-bridge/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ prost = { workspace = true }
rand = "0.10"
rand_pcg = "0.10"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_json = { workspace = true }
tokio = "1.47"
tokio-stream = "0.1"
tokio-util = "0.7"
Expand Down
2 changes: 1 addition & 1 deletion crates/sdk-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ reqwest = { version = "0.13", features = [
"rustls",
], default-features = false, optional = true }
serde = "1.0"
serde_json = "1.0"
serde_json = { workspace = true }
siphasher = "1.0"
slotmap = "1.0"
sysinfo = { version = "0.38", default-features = false, features = ["system"] }
Expand Down
7 changes: 5 additions & 2 deletions crates/sdk-core/src/test_help/integ_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

pub use crate::{
internal_flags::CoreInternalFlags,
worker::{LEGACY_QUERY_ID, client::mocks::mock_worker_client},
worker::{
LEGACY_QUERY_ID,
client::{LegacyQueryResult, mocks::mock_worker_client},
},
};

use crate::{
Expand All @@ -16,7 +19,7 @@ use crate::{
sticky_q_name_for_worker,
worker::{
TaskPollers, WorkerTelemetry,
client::{LegacyQueryResult, MockWorkerClient, WorkerClient, WorkflowTaskCompletion},
client::{MockWorkerClient, WorkerClient, WorkflowTaskCompletion},
worker_config_builder,
},
};
Expand Down
3 changes: 3 additions & 0 deletions crates/sdk-core/src/worker/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,11 @@ use uuid::Uuid;

type Result<T, E = tonic::Status> = std::result::Result<T, E>;

/// The result of a legacy query sent via `respond_legacy_query`.
pub enum LegacyQueryResult {
/// The query handler returned a result successfully.
Succeeded(QueryResult),
/// The query handler failed.
Failed(workflow_completion::Failure),
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ use temporalio_common::{
protos::{
DEFAULT_ACTIVITY_TYPE, DEFAULT_WORKFLOW_TYPE, TestHistoryBuilder, canned_histories,
coresdk::{
ActivityHeartbeat, ActivityTaskCompletion, IntoCompletion, IntoPayloadsExt,
ActivityHeartbeat, ActivityTaskCompletion, AsJsonPayloadExt, IntoCompletion,
IntoPayloadsExt,
activity_result::{
self, ActivityExecutionResult, ActivityResolution, activity_resolution as act_res,
},
Expand Down Expand Up @@ -1286,7 +1287,7 @@ async fn pass_activity_summary_to_metadata() {
let wf_id = mock_cfg.hists[0].wf_id.clone();
let wf_type = DEFAULT_WORKFLOW_TYPE;
let expected_user_metadata = Some(UserMetadata {
summary: Some(b"activity summary".into()),
summary: Some("activity summary".as_json_payload().unwrap()),
details: None,
});
mock_cfg.completion_asserts_from_expectations(|mut asserts| {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -640,8 +640,8 @@ async fn pass_child_workflow_summary_to_metadata() {
let t = canned_histories::single_child_workflow(wf_id);
let mut mock_cfg = MockPollCfg::from_hist_builder(t);
let expected_user_metadata = Some(UserMetadata {
summary: Some(b"child summary".into()),
details: Some(b"child details".into()),
summary: Some("child summary".as_json_payload().unwrap()),
details: Some("child details".as_json_payload().unwrap()),
});
mock_cfg.completion_asserts_from_expectations(|mut asserts| {
asserts
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::common::CoreWfStarter;
use temporalio_client::{
UntypedQuery, UntypedSignal, UntypedUpdate, WorkflowExecuteUpdateOptions, WorkflowQueryOptions,
WorkflowSignalOptions, WorkflowStartOptions,
UntypedQuery, UntypedSignal, UntypedUpdate, WorkflowDescribeOptions,
WorkflowExecuteUpdateOptions, WorkflowQueryOptions, WorkflowSignalOptions,
WorkflowStartOptions,
};
use temporalio_common::{
data_converters::{PayloadConverter, RawValue},
Expand Down Expand Up @@ -620,3 +621,52 @@ async fn test_typed_signal_query_update() {
let result = handle.get_result(Default::default()).await.unwrap();
assert_eq!(result.counter, 100);
}

#[workflow]
#[derive(Default)]
struct ImmediatelyCompletingWf;

#[workflow_methods]
impl ImmediatelyCompletingWf {
#[run]
async fn run(_ctx: &mut WorkflowContext<Self>) -> WorkflowResult<()> {
Ok(())
}
}

/// Verify that `static_summary` and `static_details` set in `WorkflowStartOptions` are
/// stored on the server and visible via `DescribeWorkflowExecution`.
#[tokio::test]
async fn static_summary_and_details_visible_after_start() {
let wf_name = "static_summary_and_details_visible_after_start";
let mut starter = CoreWfStarter::new(wf_name);
starter.sdk_config.task_types = WorkerTaskTypes::workflow_only();
let mut worker = starter.worker().await;
worker.register_workflow::<ImmediatelyCompletingWf>();

let task_queue = starter.get_task_queue().to_owned();
let handle = worker
.submit_workflow(
ImmediatelyCompletingWf::run,
(),
WorkflowStartOptions::new(task_queue, wf_name)
.static_summary("my static summary")
.static_details("my static details")
.build(),
)
.await
.unwrap();

worker.run_until_done().await.unwrap();

let description = handle
.describe(WorkflowDescribeOptions::default())
.await
.unwrap();

let summary = description.static_summary().expect("summary present");
assert_eq!(summary, "my static summary",);

let details = description.static_details().expect("details present");
assert_eq!(details, "my static details",);
}
Loading
Loading