Skip to content

Commit 5d64818

Browse files
Fix javadoc for ActivityExecutionContext.getHeartbeatDetails​ (#2525)
Fix javadoc for ActivityExecutionContext.getHeartbeatDetails​ and add getLastHeartbeatDetails
1 parent 0b88507 commit 5d64818

File tree

8 files changed

+100
-19
lines changed

8 files changed

+100
-19
lines changed

temporal-kotlin/src/main/kotlin/io/temporal/activity/ActivityExecutionContextExt.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import kotlin.reflect.javaType
55
import kotlin.reflect.typeOf
66

77
/**
8-
* Extracts Heartbeat details from the last failed attempt.
8+
* Extracts heartbeat details from the last heartbeat of the current activity attempt or from the
9+
* last failed attempt if no heartbeats were sent yet.
910
*
1011
* @param T type of the Heartbeat details
1112
* @see ActivityExecutionContext.getHeartbeatDetails

temporal-sdk/src/main/java/io/temporal/activity/ActivityExecutionContext.java

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,33 +33,56 @@ public interface ActivityExecutionContext {
3333
<V> void heartbeat(V details) throws ActivityCompletionException;
3434

3535
/**
36-
* Extracts Heartbeat details from the last failed attempt. This is used in combination with retry
37-
* options. An Activity Execution could be scheduled with optional {@link
38-
* io.temporal.common.RetryOptions} via {@link io.temporal.activity.ActivityOptions}. If an
39-
* Activity Execution failed then the server would attempt to dispatch another Activity Task to
40-
* retry the execution according to the retry options. If there were Heartbeat details reported by
41-
* the last Activity Execution that failed, they would be delivered along with the Activity Task
42-
* for the next retry attempt and can be extracted by the Activity implementation.
36+
* Extracts Heartbeat details from the last heartbeat of this Activity Execution attempt. If there
37+
* were no heartbeats in this attempt, details from the last failed attempt are returned instead.
38+
* This is used in combination with retry options. An Activity Execution could be scheduled with
39+
* optional {@link io.temporal.common.RetryOptions} via {@link
40+
* io.temporal.activity.ActivityOptions}. If an Activity Execution failed then the server would
41+
* attempt to dispatch another Activity Task to retry the execution according to the retry
42+
* options. If there were Heartbeat details reported by the last Activity Execution that failed,
43+
* they would be delivered along with the Activity Task for the next retry attempt and can be
44+
* extracted by the Activity implementation.
4345
*
4446
* @param detailsClass Class of the Heartbeat details
4547
*/
4648
<V> Optional<V> getHeartbeatDetails(Class<V> detailsClass);
4749

4850
/**
49-
* Extracts Heartbeat details from the last failed attempt. This is used in combination with retry
50-
* options. An Activity Execution could be scheduled with optional {@link
51-
* io.temporal.common.RetryOptions} via {@link io.temporal.activity.ActivityOptions}. If an
52-
* Activity Execution failed then the server would attempt to dispatch another Activity Task to
53-
* retry the execution according to the retry options. If there were Heartbeat details reported by
54-
* the last Activity Execution that failed, the details would be delivered along with the Activity
55-
* Task for the next retry attempt. The Activity implementation can extract the details via {@link
56-
* #getHeartbeatDetails(Class)}() and resume progress.
51+
* Extracts Heartbeat details from the last heartbeat of this Activity Execution attempt. If there
52+
* were no heartbeats in this attempt, details from the last failed attempt are returned instead.
53+
* It is useful in combination with retry options. An Activity Execution could be scheduled with
54+
* optional {@link io.temporal.common.RetryOptions} via {@link
55+
* io.temporal.activity.ActivityOptions}. If an Activity Execution failed then the server would
56+
* attempt to dispatch another Activity Task to retry the execution according to the retry
57+
* options. If there were Heartbeat details reported by the last Activity Execution that failed,
58+
* the details would be delivered along with the Activity Task for the next retry attempt. The
59+
* Activity implementation can extract the details via {@link #getHeartbeatDetails(Class)}() and
60+
* resume progress.
5761
*
5862
* @param detailsClass Class of the Heartbeat details
5963
* @param detailsGenericType Type of the Heartbeat details
6064
*/
6165
<V> Optional<V> getHeartbeatDetails(Class<V> detailsClass, Type detailsGenericType);
6266

67+
/**
68+
* Returns details from the last failed attempt of this Activity Execution. Unlike {@link
69+
* #getHeartbeatDetails(Class)}, the returned details are not updated on every heartbeat call
70+
* within the current attempt.
71+
*
72+
* @param detailsClass Class of the Heartbeat details
73+
*/
74+
<V> Optional<V> getLastHeartbeatDetails(Class<V> detailsClass);
75+
76+
/**
77+
* Returns details from the last failed attempt of this Activity Execution. Unlike {@link
78+
* #getHeartbeatDetails(Class, Type)}, the returned details are not updated on every heartbeat
79+
* call within the current attempt.
80+
*
81+
* @param detailsClass Class of the Heartbeat details
82+
* @param detailsGenericType Type of the Heartbeat details
83+
*/
84+
<V> Optional<V> getLastHeartbeatDetails(Class<V> detailsClass, Type detailsGenericType);
85+
6386
/**
6487
* Gets a correlation token that can be used to complete the Activity Execution asynchronously
6588
* through {@link io.temporal.client.ActivityCompletionClient#complete(byte[], Object)}.

temporal-sdk/src/main/java/io/temporal/common/interceptors/ActivityExecutionContextBase.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@ public <V> Optional<V> getHeartbeatDetails(Class<V> detailsClass, Type detailsGe
3737
return next.getHeartbeatDetails(detailsClass, detailsGenericType);
3838
}
3939

40+
@Override
41+
public <V> Optional<V> getLastHeartbeatDetails(Class<V> detailsClass) {
42+
return next.getLastHeartbeatDetails(detailsClass);
43+
}
44+
45+
@Override
46+
public <V> Optional<V> getLastHeartbeatDetails(Class<V> detailsClass, Type detailsGenericType) {
47+
return next.getLastHeartbeatDetails(detailsClass, detailsGenericType);
48+
}
49+
4050
@Override
4151
public byte[] getTaskToken() {
4252
return next.getTaskToken();

temporal-sdk/src/main/java/io/temporal/internal/activity/ActivityExecutionContextImpl.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,17 @@ public <V> Optional<V> getHeartbeatDetails(Class<V> detailsClass, Type detailsGe
8989
return heartbeatContext.getHeartbeatDetails(detailsClass, detailsGenericType);
9090
}
9191

92+
@Override
93+
public <V> Optional<V> getLastHeartbeatDetails(Class<V> detailsClass) {
94+
return getLastHeartbeatDetails(detailsClass, detailsClass);
95+
}
96+
97+
@Override
98+
@SuppressWarnings("unchecked")
99+
public <V> Optional<V> getLastHeartbeatDetails(Class<V> detailsClass, Type detailsGenericType) {
100+
return heartbeatContext.getLastHeartbeatDetails(detailsClass, detailsGenericType);
101+
}
102+
92103
@Override
93104
public byte[] getTaskToken() {
94105
return info.getTaskToken();
@@ -153,7 +164,7 @@ public ActivityInfo getInfo() {
153164

154165
@Override
155166
public Object getLastHeartbeatValue() {
156-
return heartbeatContext.getLastHeartbeatDetails();
167+
return heartbeatContext.getLatestHeartbeatDetails();
157168
}
158169

159170
@Override

temporal-sdk/src/main/java/io/temporal/internal/activity/HeartbeatContext.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@ interface HeartbeatContext {
1616
*/
1717
<V> Optional<V> getHeartbeatDetails(Class<V> detailsClass, Type detailsGenericType);
1818

19-
Object getLastHeartbeatDetails();
19+
/**
20+
* @see io.temporal.activity.ActivityExecutionContext#getLastHeartbeatDetails(Class)
21+
*/
22+
<V> Optional<V> getLastHeartbeatDetails(Class<V> detailsClass, Type detailsGenericType);
23+
24+
Object getLatestHeartbeatDetails();
2025

2126
/** Cancel any pending heartbeat and discard cached heartbeat details. */
2227
void cancelOutstandingHeartbeat();

temporal-sdk/src/main/java/io/temporal/internal/activity/HeartbeatContextImpl.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,24 @@ public <V> Optional<V> getHeartbeatDetails(Class<V> detailsClass, Type detailsGe
130130
}
131131
}
132132

133+
/**
134+
* @see ActivityExecutionContext#getLastHeartbeatDetails(Class, Type)
135+
*/
136+
@Override
137+
@SuppressWarnings("unchecked")
138+
public <V> Optional<V> getLastHeartbeatDetails(Class<V> detailsClass, Type detailsGenericType) {
139+
lock.lock();
140+
try {
141+
return Optional.ofNullable(
142+
dataConverterWithActivityContext.fromPayloads(
143+
0, prevAttemptHeartbeatDetails, detailsClass, detailsGenericType));
144+
} finally {
145+
lock.unlock();
146+
}
147+
}
148+
133149
@Override
134-
public Object getLastHeartbeatDetails() {
150+
public Object getLatestHeartbeatDetails() {
135151
lock.lock();
136152
try {
137153
if (receivedAHeartbeat) {

temporal-sdk/src/main/java/io/temporal/internal/activity/LocalActivityExecutionContextImpl.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,16 @@ public <V> Optional<V> getHeartbeatDetails(Class<V> detailsClass, Type detailsGe
4242
return Optional.empty();
4343
}
4444

45+
@Override
46+
public <V> Optional<V> getLastHeartbeatDetails(Class<V> detailsClass) {
47+
return Optional.empty();
48+
}
49+
50+
@Override
51+
public <V> Optional<V> getLastHeartbeatDetails(Class<V> detailsClass, Type detailsGenericType) {
52+
return Optional.empty();
53+
}
54+
4555
@Override
4656
public byte[] getTaskToken() {
4757
throw new UnsupportedOperationException("getTaskToken is not supported for local activities");

temporal-sdk/src/test/java/io/temporal/activity/ActivityHeartbeatSentOnFailureTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import io.temporal.workflow.Workflow;
66
import io.temporal.workflow.shared.TestActivities;
77
import io.temporal.workflow.shared.TestWorkflows;
8+
import org.junit.Assert;
89
import org.junit.Rule;
910
import org.junit.Test;
1011

@@ -43,6 +44,10 @@ public static class HeartBeatingActivityImpl implements TestActivities.NoArgsAct
4344
public void execute() {
4445
// If the heartbeat details are "3", then we know that the last heartbeat was sent.
4546
if (Activity.getExecutionContext().getHeartbeatDetails(String.class).orElse("").equals("3")) {
47+
Activity.getExecutionContext().heartbeat("1");
48+
// Verify that last heartbeat details don't change after a heartbeat
49+
Assert.assertEquals(
50+
"3", Activity.getExecutionContext().getLastHeartbeatDetails(String.class).orElse(""));
4651
return;
4752
}
4853
// Send 3 heartbeats and then fail, expecting the last heartbeat to be sent

0 commit comments

Comments
 (0)