diff --git a/changelog/fixed/stopwatch-sloth.md b/changelog/fixed/stopwatch-sloth.md new file mode 100644 index 00000000..41152d42 --- /dev/null +++ b/changelog/fixed/stopwatch-sloth.md @@ -0,0 +1 @@ +Time search attribute values now keep sub-second precision, and setting one no longer raises `NoMethodError` when the application has not required `time`. diff --git a/temporalio/lib/temporalio/search_attributes.rb b/temporalio/lib/temporalio/search_attributes.rb index 32b05bad..ac5c6ae7 100644 --- a/temporalio/lib/temporalio/search_attributes.rb +++ b/temporalio/lib/temporalio/search_attributes.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'temporalio/api' +require 'time' module Temporalio # Collection of typed search attributes. @@ -142,8 +143,9 @@ def self._value_from_payload(payload) # @!visibility private def self._to_proto_pair(key, value) - # We use a default converter, but if type is a time, we need ISO format - value = value.iso8601 if key.type == IndexedValueType::TIME && value.is_a?(Time) + # We use a default converter, but if type is a time, we need ISO format with nanoseconds since the server keeps + # sub-second precision + value = value.iso8601(9) if key.type == IndexedValueType::TIME && value.is_a?(Time) # Convert to payload payload = Converters::PayloadConverter.default.to_payload(value) diff --git a/temporalio/test/client_workflow_test.rb b/temporalio/test/client_workflow_test.rb index e481ae82..2cec8c57 100644 --- a/temporalio/test/client_workflow_test.rb +++ b/temporalio/test/client_workflow_test.rb @@ -122,6 +122,23 @@ def test_lazy_connect assert client.connection.connected? end + exclude_from_cloud :needs_cloud_adaptation, + 'Requires custom search attributes that the Cloud harness does not provision.' + def test_search_attribute_time_sub_second + env.ensure_common_search_attribute_keys + + time = Time.at(1_800_000_000, 123_456_789, :nanosecond, in: 'UTC') + handle = env.client.start_workflow( + 'does-not-exist', + id: "wf-#{SecureRandom.uuid}", + task_queue: "tq-#{SecureRandom.uuid}", + search_attributes: Temporalio::SearchAttributes.new({ ATTR_KEY_TIME => time }) + ) + assert_equal time, handle.describe.search_attributes&.[](ATTR_KEY_TIME) + ensure + handle&.terminate + end + exclude_from_cloud :needs_cloud_adaptation, 'Requires custom search attributes and a Go worker with Cloud TLS configuration.' def test_describe