From cab9d458db9b68347c48e9113d360dbb285fd603 Mon Sep 17 00:00:00 2001 From: Luke Butters Date: Tue, 16 Jun 2026 16:40:17 +1000 Subject: [PATCH 1/2] Default polling workers to 5 TCP connections instead of 1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Polling Tentacle workers previously opened a single TCP connection to Octopus Server, serialising all RPC calls. This causes queue time growth and deployment failures for high-throughput customers (e.g. DRB). This change sets the default to 5 connections — matching the k8s polling worker default that is already proven in production. Customers can still override via TentaclePollingConnectionCount env var; Halibut's MaximumActiveTcpConnectionsPerPollingSubscription cap remains in place. Co-Authored-By: Claude Sonnet 4.6 --- .../Communications/HalibutInitializer.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/source/Octopus.Tentacle/Communications/HalibutInitializer.cs b/source/Octopus.Tentacle/Communications/HalibutInitializer.cs index 92ca8982e..0b44b7f95 100644 --- a/source/Octopus.Tentacle/Communications/HalibutInitializer.cs +++ b/source/Octopus.Tentacle/Communications/HalibutInitializer.cs @@ -115,19 +115,18 @@ void AddPollingEndpoints() } } - const int MaximumPollingConnectionCount = 8; - + const uint DefaultPollingConnectionCount = 5; + const uint MaximumPollingConnectionCount = 8; + uint GetPollingConnectionCount() { - //Open multiple polling connections if the env var is set to a non-zero/negative number - var connectionCount = 1u; + var connectionCount = DefaultPollingConnectionCount; if (uint.TryParse(Environment.GetEnvironmentVariable(EnvironmentVariables.TentaclePollingConnectionCount), out var count)) { log.InfoFormat("Requested polling connection count: {0}", count); connectionCount = count; } - //Coerce the requested value as it might be outside our max & min switch (connectionCount) { case > MaximumPollingConnectionCount: From aa7f003a79ce506548916a85f08fb137944c614d Mon Sep 17 00:00:00 2001 From: Luke Butters Date: Wed, 17 Jun 2026 11:03:28 +1000 Subject: [PATCH 2/2] Only apply multi-connection default when Tentacle is a worker Persist IsWorker=true to config on register-worker and false on register-with. HalibutInitializer reads this flag so deployment targets keep their existing single-connection behaviour. Co-Authored-By: Claude Sonnet 4.6 --- .../Commands/RegisterMachineCommandBase.cs | 3 +++ .../Commands/RegisterWorkerCommandBase.cs | 2 ++ .../Octopus.Tentacle/Communications/HalibutInitializer.cs | 2 +- .../Configuration/ITentacleConfiguration.cs | 4 ++++ .../Configuration/TentacleConfiguration.cs | 8 ++++++++ 5 files changed, 18 insertions(+), 1 deletion(-) diff --git a/source/Octopus.Tentacle/Commands/RegisterMachineCommandBase.cs b/source/Octopus.Tentacle/Commands/RegisterMachineCommandBase.cs index 02a96e28c..72f07f6db 100644 --- a/source/Octopus.Tentacle/Commands/RegisterMachineCommandBase.cs +++ b/source/Octopus.Tentacle/Commands/RegisterMachineCommandBase.cs @@ -177,11 +177,14 @@ async Task RegisterMachine(IOctopusSystemAsyncRepository systemRepository, IOcto } configuration.Value.AddOrUpdateTrustedOctopusServer(server); + configuration.Value.SetIsWorker(IsRegisteredAsWorker); VoteForRestart(); log.Info("Machine registered successfully"); } + protected virtual bool IsRegisteredAsWorker => false; + protected abstract void CheckArgs(); protected abstract void EnhanceOperation(TRegistrationOperationType registerOperation); diff --git a/source/Octopus.Tentacle/Commands/RegisterWorkerCommandBase.cs b/source/Octopus.Tentacle/Commands/RegisterWorkerCommandBase.cs index add9a363d..bfb92c810 100644 --- a/source/Octopus.Tentacle/Commands/RegisterWorkerCommandBase.cs +++ b/source/Octopus.Tentacle/Commands/RegisterWorkerCommandBase.cs @@ -29,6 +29,8 @@ public RegisterWorkerCommandBase(Lazy lazyRegisterMach Options.Add("workerpool=", "The worker pool name, slug or Id to add the machine to - e.g., 'Windows Pool'; specify this argument multiple times to add to multiple pools", s => workerpools.Add(s)); } + protected override bool IsRegisteredAsWorker => true; + protected override void CheckArgs() { if (workerpools.Count == 0 || string.IsNullOrWhiteSpace(workerpools.First())) diff --git a/source/Octopus.Tentacle/Communications/HalibutInitializer.cs b/source/Octopus.Tentacle/Communications/HalibutInitializer.cs index 0b44b7f95..a2d4d9953 100644 --- a/source/Octopus.Tentacle/Communications/HalibutInitializer.cs +++ b/source/Octopus.Tentacle/Communications/HalibutInitializer.cs @@ -120,7 +120,7 @@ void AddPollingEndpoints() uint GetPollingConnectionCount() { - var connectionCount = DefaultPollingConnectionCount; + var connectionCount = configuration.IsWorker ? DefaultPollingConnectionCount : 1u; if (uint.TryParse(Environment.GetEnvironmentVariable(EnvironmentVariables.TentaclePollingConnectionCount), out var count)) { log.InfoFormat("Requested polling connection count: {0}", count); diff --git a/source/Octopus.Tentacle/Configuration/ITentacleConfiguration.cs b/source/Octopus.Tentacle/Configuration/ITentacleConfiguration.cs index 675b657bb..63907eb02 100644 --- a/source/Octopus.Tentacle/Configuration/ITentacleConfiguration.cs +++ b/source/Octopus.Tentacle/Configuration/ITentacleConfiguration.cs @@ -75,6 +75,8 @@ public interface ITentacleConfiguration bool IsRegistered { get; } + bool IsWorker { get; } + void WriteTo(IWritableKeyValueStore outputStore, IEnumerable excluding); } @@ -92,6 +94,8 @@ public interface IWritableTentacleConfiguration : ITentacleConfiguration bool SetIsRegistered(bool isRegistered = true); + bool SetIsWorker(bool isWorker = true); + /// /// Sets the IP address to listen on. /// diff --git a/source/Octopus.Tentacle/Configuration/TentacleConfiguration.cs b/source/Octopus.Tentacle/Configuration/TentacleConfiguration.cs index e74380aa8..a358a5e56 100644 --- a/source/Octopus.Tentacle/Configuration/TentacleConfiguration.cs +++ b/source/Octopus.Tentacle/Configuration/TentacleConfiguration.cs @@ -19,6 +19,7 @@ namespace Octopus.Tentacle.Configuration internal class TentacleConfiguration : ITentacleConfiguration { internal const string IsRegisteredSettingName = "Tentacle.Services.IsRegistered"; + internal const string IsWorkerSettingName = "Tentacle.Services.IsWorker"; internal const string ServicesPortSettingName = "Tentacle.Services.PortNumber"; internal const string ServicesListenIPSettingName = "Tentacle.Services.ListenIP"; internal const string ServicesNoListenSettingName = "Tentacle.Services.NoListen"; @@ -70,6 +71,8 @@ public IEnumerable TrustedOctopusThumbprints public bool IsRegistered => settings.Get(IsRegisteredSettingName, false); + public bool IsWorker => settings.Get(IsWorkerSettingName, false); + public void WriteTo(IWritableKeyValueStore outputStore, IEnumerable excluding) { excluding = new HashSet(excluding); @@ -191,6 +194,11 @@ public bool SetIsRegistered(bool isRegistered = true) return settings.Set(IsRegisteredSettingName, isRegistered); } + public bool SetIsWorker(bool isWorker = true) + { + return settings.Set(IsWorkerSettingName, isWorker); + } + public bool SetListenIpAddress(string? address) { return settings.Set(ServicesListenIPSettingName, address);