diff --git a/src/Runner.Listener/Runner.cs b/src/Runner.Listener/Runner.cs index 5ef0a3d64..1b145be5d 100644 --- a/src/Runner.Listener/Runner.cs +++ b/src/Runner.Listener/Runner.cs @@ -1,18 +1,18 @@ -using GitHub.DistributedTask.WebApi; -using GitHub.Runner.Listener.Configuration; using System; -using System.Threading; -using System.Threading.Tasks; -using GitHub.Services.WebApi; -using Pipelines = GitHub.DistributedTask.Pipelines; +using System.Collections.Generic; using System.IO; +using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using GitHub.DistributedTask.WebApi; using GitHub.Runner.Common; -using GitHub.Runner.Sdk; -using System.Linq; using GitHub.Runner.Listener.Check; -using System.Collections.Generic; +using GitHub.Runner.Listener.Configuration; +using GitHub.Runner.Sdk; +using GitHub.Services.WebApi; +using Pipelines = GitHub.DistributedTask.Pipelines; namespace GitHub.Runner.Listener { @@ -322,6 +322,7 @@ namespace GitHub.Runner.Listener // Should we try to cleanup ephemeral runners bool runOnceJobCompleted = false; + bool skipSessionDeletion = false; try { var notification = HostContext.GetService(); @@ -468,6 +469,14 @@ namespace GitHub.Runner.Listener Trace.Info($"Skip message deletion for cancellation message '{message.MessageId}'."); } } + else if (string.Equals(message.MessageType, Pipelines.HostedRunnerShutdownMessage.MessageType, StringComparison.OrdinalIgnoreCase)) + { + var HostedRunnerShutdownMessage = JsonUtility.FromString(message.Body); + skipMessageDeletion = true; + skipSessionDeletion = true; + Trace.Info($"Service requests the hosted runner to shutdown. Reason: '{HostedRunnerShutdownMessage.Reason}'."); + return Constants.Runner.ReturnCode.Success; + } else { Trace.Error($"Received message {message.MessageId} with unsupported message type {message.MessageType}."); @@ -501,15 +510,18 @@ namespace GitHub.Runner.Listener await jobDispatcher.ShutdownAsync(); } - try + if (!skipSessionDeletion) { - await _listener.DeleteSessionAsync(); - } - catch (Exception ex) when (runOnce) - { - // ignore exception during delete session for ephemeral runner since the runner might already be deleted from the server side - // and the delete session call will ends up with 401. - Trace.Info($"Ignore any exception during DeleteSession for an ephemeral runner. {ex}"); + try + { + await _listener.DeleteSessionAsync(); + } + catch (Exception ex) when (runOnce) + { + // ignore exception during delete session for ephemeral runner since the runner might already be deleted from the server side + // and the delete session call will ends up with 401. + Trace.Info($"Ignore any exception during DeleteSession for an ephemeral runner. {ex}"); + } } messageQueueLoopTokenSource.Dispose(); diff --git a/src/Sdk/DTPipelines/Pipelines/RunnerShutdownMessage.cs b/src/Sdk/DTPipelines/Pipelines/RunnerShutdownMessage.cs new file mode 100644 index 000000000..af9217e34 --- /dev/null +++ b/src/Sdk/DTPipelines/Pipelines/RunnerShutdownMessage.cs @@ -0,0 +1,39 @@ +using System; +using System.Runtime.Serialization; +using GitHub.Services.WebApi; +using Newtonsoft.Json; + +namespace GitHub.DistributedTask.Pipelines +{ + [DataContract] + public sealed class HostedRunnerShutdownMessage + { + public static readonly String MessageType = "RunnerShutdown"; + + [JsonConstructor] + internal HostedRunnerShutdownMessage() + { + } + + public HostedRunnerShutdownMessage(String reason) + { + this.Reason = reason; + } + + [DataMember] + public String Reason + { + get; + private set; + } + + public WebApi.TaskAgentMessage GetAgentMessage() + { + return new WebApi.TaskAgentMessage + { + Body = JsonUtility.ToString(this), + MessageType = HostedRunnerShutdownMessage.MessageType, + }; + } + } +} \ No newline at end of file