From 5c8a24078a0ce831791f79644ded51c24eaf5125 Mon Sep 17 00:00:00 2001 From: Markus Szumovski Date: Wed, 12 Jul 2023 15:37:52 +0200 Subject: [PATCH 1/2] do not start a second GetNextMessageAsync thread in case one is already running --- src/Agent.Listener/Agent.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Agent.Listener/Agent.cs b/src/Agent.Listener/Agent.cs index 7628352679..92e8a1fb3c 100644 --- a/src/Agent.Listener/Agent.cs +++ b/src/Agent.Listener/Agent.cs @@ -15,6 +15,7 @@ using System.IO; using System.Reflection; using System.Runtime.CompilerServices; +using Microsoft.VisualStudio.Services.Common; namespace Microsoft.VisualStudio.Services.Agent.Listener { @@ -325,13 +326,20 @@ private async Task RunAsync(AgentSettings settings, bool runOnce = false) jobDispatcher = HostContext.CreateService(); TaskAgentMessage previuosMessage = null; + Task getNextMessage = null; while (!HostContext.AgentShutdownToken.IsCancellationRequested) { TaskAgentMessage message = null; bool skipMessageDeletion = false; try { - Task getNextMessage = _listener.GetNextMessageAsync(messageQueueLoopTokenSource.Token); + if(getNextMessage == null || (getNextMessage.Status != TaskStatus.Running && + getNextMessage.Status != TaskStatus.WaitingForChildrenToComplete && + getNextMessage.Status != TaskStatus.WaitingForActivation && + getNextMessage.Status != TaskStatus.WaitingToRun)) + { + getNextMessage = _listener.GetNextMessageAsync(messageQueueLoopTokenSource.Token); + } if (autoUpdateInProgress) { Trace.Verbose("Auto update task running at backend, waiting for getNextMessage or selfUpdateTask to finish."); From 27055a8df8c6ee31ebfcde538cdb3dfd57871955 Mon Sep 17 00:00:00 2001 From: Markus Szumovski Date: Fri, 14 Jul 2023 14:01:26 +0200 Subject: [PATCH 2/2] Added possibility to enable message queue polling cycle bugfix via environment knob --- src/Agent.Listener/Agent.cs | 15 +++++++++++---- src/Agent.Sdk/Knob/AgentKnobs.cs | 6 ++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/Agent.Listener/Agent.cs b/src/Agent.Listener/Agent.cs index 92e8a1fb3c..30787fe40d 100644 --- a/src/Agent.Listener/Agent.cs +++ b/src/Agent.Listener/Agent.cs @@ -16,6 +16,7 @@ using System.Reflection; using System.Runtime.CompilerServices; using Microsoft.VisualStudio.Services.Common; +using Agent.Sdk.Knob; namespace Microsoft.VisualStudio.Services.Agent.Listener { @@ -324,6 +325,9 @@ private async Task RunAsync(AgentSettings settings, bool runOnce = false) Task selfUpdateTask = null; bool runOnceJobReceived = false; jobDispatcher = HostContext.CreateService(); + + // check if parallel polling should be prevented + bool preventParallelPolling = AgentKnobs.PreventParallelPolling.GetValue(UtilKnobValueContext.Instance()).AsBoolean(); TaskAgentMessage previuosMessage = null; Task getNextMessage = null; @@ -333,10 +337,13 @@ private async Task RunAsync(AgentSettings settings, bool runOnce = false) bool skipMessageDeletion = false; try { - if(getNextMessage == null || (getNextMessage.Status != TaskStatus.Running && - getNextMessage.Status != TaskStatus.WaitingForChildrenToComplete && - getNextMessage.Status != TaskStatus.WaitingForActivation && - getNextMessage.Status != TaskStatus.WaitingToRun)) + // if preventing of parallel polling is enabled then check if a getNextMessage thread is already running + // and do not start a new getNextMessage thread if that is the case + if(!preventParallelPolling || + (getNextMessage == null || (getNextMessage.Status != TaskStatus.Running && + getNextMessage.Status != TaskStatus.WaitingForChildrenToComplete && + getNextMessage.Status != TaskStatus.WaitingForActivation && + getNextMessage.Status != TaskStatus.WaitingToRun))) { getNextMessage = _listener.GetNextMessageAsync(messageQueueLoopTokenSource.Token); } diff --git a/src/Agent.Sdk/Knob/AgentKnobs.cs b/src/Agent.Sdk/Knob/AgentKnobs.cs index 250a9db015..7b2e38fc66 100644 --- a/src/Agent.Sdk/Knob/AgentKnobs.cs +++ b/src/Agent.Sdk/Knob/AgentKnobs.cs @@ -385,6 +385,12 @@ public class AgentKnobs new EnvironmentKnobSource("ENABLE_VS_PRERELEASE_VERSIONS"), new BuiltInDefaultKnobSource("false")); + public static readonly Knob PreventParallelPolling = new Knob( + nameof(PreventParallelPolling), + "If true, the agent will prevent erroneous parallel polling of the agent pool message queue (currently experimental).", + new EnvironmentKnobSource("PREVENT_PARALLEL_POLLING"), + new BuiltInDefaultKnobSource("false")); + public static readonly Knob DisableOverrideTfvcBuildDirectory = new Knob( nameof(DisableOverrideTfvcBuildDirectory), "Disables override of Tfvc build directory name by agentId on hosted agents (one tfvc repo used).",