diff --git a/src/Runner.Worker/ExecutionContext.cs b/src/Runner.Worker/ExecutionContext.cs
index 5646d46aa..86aba9f1e 100644
--- a/src/Runner.Worker/ExecutionContext.cs
+++ b/src/Runner.Worker/ExecutionContext.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
@@ -95,6 +95,7 @@ namespace GitHub.Runner.Worker
// timeline record update methods
void Start(string currentOperation = null);
TaskResult Complete(TaskResult? result = null, string currentOperation = null, string resultCode = null);
+ void ResetForRerun();
void SetEnvContext(string name, string value);
void SetRunnerContext(string name, string value);
string GetGitHubContext(string name);
@@ -545,6 +546,29 @@ namespace GitHub.Runner.Worker
return Result.Value;
}
+ ///
+ /// Resets the execution context for re-running (e.g., after step-back in DAP debugging).
+ /// Creates a new CancellationTokenSource since the previous one was disposed in Complete().
+ ///
+ public void ResetForRerun()
+ {
+ // Create a new CancellationTokenSource since the old one was disposed
+ _cancellationTokenSource = new CancellationTokenSource();
+
+ // Reset record state to allow re-execution
+ _record.State = TimelineRecordState.Pending;
+ _record.FinishTime = null;
+ _record.PercentComplete = 0;
+ _record.ResultCode = null;
+
+ // Reset result
+ Result = null;
+ Outcome = null;
+
+ // Reset the force completed task
+ _forceCompleted = new TaskCompletionSource();
+ }
+
public void UpdateGlobalStepsContext()
{
// Skip if generated context name. Generated context names start with "__". After 3.2 the server will never send an empty context name.
diff --git a/src/Runner.Worker/StepsRunner.cs b/src/Runner.Worker/StepsRunner.cs
index 3a9d3d487..e2e33bae6 100644
--- a/src/Runner.Worker/StepsRunner.cs
+++ b/src/Runner.Worker/StepsRunner.cs
@@ -222,9 +222,12 @@ namespace GitHub.Runner.Worker
}
// Queue the checkpoint's step and remaining steps
+ // Reset execution context for rerun since CancellationTokenSource was disposed in Complete()
+ checkpoint.CurrentStep.ExecutionContext.ResetForRerun();
jobContext.JobSteps.Enqueue(checkpoint.CurrentStep);
foreach (var remainingStep in checkpoint.RemainingSteps)
{
+ remainingStep.ExecutionContext.ResetForRerun();
jobContext.JobSteps.Enqueue(remainingStep);
}