Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -191,16 +191,20 @@ public struct ActivityExecutionContext: Sendable {
///
/// - Parameter detailTypes: The types to convert the heartbeat details to, specified as
/// variadic generic parameters.
/// - Returns: A tuple containing the converted heartbeat details in the order specified.
/// - Returns: A tuple containing the converted heartbeat details in the order specified. Returns `nil` if there are no heartbeat details available from a previous activity attempt.
/// - Throws: Conversion errors if the number of types doesn't match the stored details or if
/// deserialization fails.
public func heartbeatDetails<each HeartbeatDetail: Sendable>(
as detailTypes: repeat (each HeartbeatDetail).Type
) async throws -> (repeat each HeartbeatDetail) {
try await self.dataConverter.convertPayloads(
) async throws -> (repeat each HeartbeatDetail)? {
guard !self.heartbeatDetails.isEmpty else {
return nil
}

return try await self.dataConverter.convertPayloads(
self.heartbeatDetails,
as: repeat (each detailTypes).self
)
) as (repeat each HeartbeatDetail)
}
}

Expand Down
67 changes: 39 additions & 28 deletions Tests/TemporalTests/Worker/Activities/ActivityWorkerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -231,21 +231,25 @@ private struct BadHeartbeatAcivity: ActivityDefinition {
}
}

private struct ReadingHeartbeatAcivity: ActivityDefinition {
private struct ReadingHeartbeatActivity: ActivityDefinition {
struct HeartbeatDetails: Codable, Hashable {
var string: String
var data: Data
}
typealias Input = Void
typealias Output = HeartbeatDetails
typealias Output = HeartbeatDetails?

static let name: String? = "ReadingHeartbeatAcivity"
static let name: String? = "ReadingHeartbeatActivity"

func run(input: Void) async throws -> HeartbeatDetails {
let (string, data) = try await ActivityExecutionContext.current!.info.heartbeatDetails(
as: String.self,
Data.self
)
func run(input: Void) async throws -> HeartbeatDetails? {
guard
let (string, data) = try await ActivityExecutionContext.current!.info.heartbeatDetails(
as: String.self,
Data.self
)
else {
return nil
}

return .init(string: string, data: data)
}
Expand Down Expand Up @@ -748,9 +752,9 @@ struct ActivityWorkerTests {
}
}

@Test
static func readingHeartbeat() async throws {
let test = ActivityWorkerTests(activities: [ReadingHeartbeatAcivity()])
@Test("Read Heartbeat Details", arguments: [true, false])
static func readingHeartbeat(heartbeatDetailsAvailable: Bool) async throws {
let test = ActivityWorkerTests(activities: [ReadingHeartbeatActivity()])

try await withThrowingTaskGroup(of: Void.self) { group in
group.addTask {
Expand All @@ -760,40 +764,47 @@ struct ActivityWorkerTests {
test.bridgeWorker.activityTaskContinuation.yield(
.with {
$0.taskToken = Data([1])
$0.start.activityType = "ReadingHeartbeatAcivity"
$0.start.activityType = "ReadingHeartbeatActivity"
$0.start.activityID = "ActivityID1"
$0.start.attempt = 1
$0.start.workflowType = "WorkflowType"
$0.start.workflowExecution = .with {
$0.runID = "RunID"
$0.workflowID = "WorkflowID1"
}
$0.start.heartbeatDetails = [
.with {
$0.data = Data(#""Foo""#.utf8)
$0.metadata = ["encoding": Data("json/plain".utf8)]
},
.with {
$0.data = Data([1, 2, 3])
$0.metadata = ["encoding": Data("binary/plain".utf8)]
},
]
if heartbeatDetailsAvailable {
$0.start.heartbeatDetails = [
.with {
$0.data = Data(#""Foo""#.utf8)
$0.metadata = ["encoding": Data("json/plain".utf8)]
},
.with {
$0.data = Data([1, 2, 3])
$0.metadata = ["encoding": Data("binary/plain".utf8)]
},
]
}
}
)

var activityTaskCompletionIterator = test.bridgeWorker.activityTaskCompletionStream.makeAsyncIterator()
let completion = try await activityTaskCompletionIterator.next()
#expect(completion?.taskToken == Data([1]))
let jsonDecoder = JSONDecoder()
let expectedHeartbeatDetails = ReadingHeartbeatAcivity.HeartbeatDetails(
string: "Foo",
data: Data([1, 2, 3])
)
let heartbeatDetails = try jsonDecoder.decode(
ReadingHeartbeatAcivity.HeartbeatDetails.self,
(ReadingHeartbeatActivity.HeartbeatDetails?).self,
from: completion!.result.completed.result.data
)
#expect(heartbeatDetails == expectedHeartbeatDetails)

if heartbeatDetailsAvailable {
let expectedHeartbeatDetails = ReadingHeartbeatActivity.HeartbeatDetails(
string: "Foo",
data: Data([1, 2, 3])
)
#expect(heartbeatDetails == expectedHeartbeatDetails)
} else {
#expect(heartbeatDetails == nil)
}
group.cancelAll()
}
}
Expand Down
Loading