|
9 | 9 | "go.temporal.io/server/common/resource" |
10 | 10 | "go.temporal.io/server/common/util" |
11 | 11 | "go.uber.org/fx" |
| 12 | + "google.golang.org/protobuf/types/known/timestamppb" |
12 | 13 | ) |
13 | 14 |
|
14 | 15 | type activityDispatchTaskExecutorOptions struct { |
@@ -159,41 +160,43 @@ func newHeartbeatTimeoutTaskExecutor() *heartbeatTimeoutTaskExecutor { |
159 | 160 | func (e *heartbeatTimeoutTaskExecutor) Validate( |
160 | 161 | ctx chasm.Context, |
161 | 162 | activity *Activity, |
162 | | - _ chasm.TaskAttributes, |
| 163 | + taskAttrs chasm.TaskAttributes, |
163 | 164 | task *activitypb.HeartbeatTimeoutTask, |
164 | 165 | ) (bool, error) { |
165 | 166 | validStatus := activity.Status == activitypb.ACTIVITY_EXECUTION_STATUS_STARTED || |
166 | 167 | activity.Status == activitypb.ACTIVITY_EXECUTION_STATUS_CANCEL_REQUESTED |
167 | | - return validStatus && activity.LastAttempt.Get(ctx).GetCount() == task.Attempt, nil |
| 168 | + if !validStatus || activity.LastAttempt.Get(ctx).GetCount() != task.Attempt { |
| 169 | + return false, nil |
| 170 | + } |
| 171 | + // High-water-mark: reject tasks that have already been executed. |
| 172 | + hwm := activity.GetLastHeartbeatTaskScheduledTime().AsTime() |
| 173 | + return taskAttrs.ScheduledTime.After(hwm), nil |
168 | 174 | } |
169 | 175 |
|
170 | 176 | // Execute executes a HeartbeatTimeoutTask. |
171 | 177 | func (e *heartbeatTimeoutTaskExecutor) Execute( |
172 | 178 | ctx chasm.MutableContext, |
173 | 179 | activity *Activity, |
174 | | - _ chasm.TaskAttributes, |
| 180 | + taskAttrs chasm.TaskAttributes, |
175 | 181 | _ *activitypb.HeartbeatTimeoutTask, |
176 | 182 | ) error { |
177 | | - // Let T = user-configured heartbeat timeout and let hb_i be the time of the ith user-submitted |
178 | | - // heartbeat request. (hb_0 = 0 since we always start a timer task when an attempt starts). |
179 | | - |
180 | 183 | // There are two concurrent processes: |
181 | | - // 1. A worker is sending heartbeats at times hb_i. |
| 184 | + // 1. A worker is sending heartbeats. |
182 | 185 | // 2. This task is being executed at (shortly after) certain scheduled times. |
183 | 186 |
|
184 | 187 | // Each time we execute this function, our task is to look back into the past and determine |
185 | | - // whether more than T has elapsed since the last heartbeat. If it has, we fail the attempt (and |
186 | | - // decide between retrying or failing the activity). If it has not, then we schedule a new timer |
187 | | - // task to execute this function at the new deadline, i.e. lastHeartbeatTime+HeartbeatTimeout. |
188 | | - // |
189 | | - // Task validation has established that an attempt is currently in progress and that it is the |
190 | | - // attempt for which this heartbeat timer was originally set. |
| 188 | + // whether more than (user-configured heartbeat timeout) has elapsed since the last heartbeat. |
| 189 | + // If it has, we fail the attempt (and decide between retrying or failing the activity). If it |
| 190 | + // has not, then we schedule a new timer task to execute this function at the new deadline. |
| 191 | + |
| 192 | + // Update high-water-mark so this task is invalidated after execution. |
| 193 | + activity.LastHeartbeatTaskScheduledTime = timestamppb.New(taskAttrs.ScheduledTime) |
191 | 194 |
|
192 | 195 | attempt := activity.LastAttempt.Get(ctx) |
193 | | - lastHb, _ := activity.LastHeartbeat.TryGet(ctx) |
194 | 196 | hbTimeout := activity.GetHeartbeatTimeout().AsDuration() |
195 | 197 | attemptStartTime := attempt.GetStartedTime().AsTime() |
196 | | - lastHbTime := lastHb.GetRecordedTime().AsTime() // could be from a previous attempt or could be zero |
| 198 | + heartbeat, _ := activity.LastHeartbeat.TryGet(ctx) |
| 199 | + lastHbTime := heartbeat.GetRecordedTime().AsTime() // could be from a previous attempt or could be zero |
197 | 200 | // No heartbeats in the attempt so far is equivalent to a heartbeat having been sent at attempt |
198 | 201 | // start time. |
199 | 202 | hbDeadline := util.MaxTime(lastHbTime, attemptStartTime).Add(hbTimeout) |
|
0 commit comments