From fb48ae1c5593c82d479e4718735185c9b73edbf2 Mon Sep 17 00:00:00 2001 From: Ramgopal Nagaboina Date: Tue, 8 Sep 2026 23:11:30 -0400 Subject: [PATCH] outofbandmanagement: run the power-state background task in a managed context The per-host power-state sync submitted to the background executor was a plain Runnable, so the database connection its DB work acquires on the worker thread was never released back to the pool. Over time one leaked connection per configured host per run exhausted the pool (HikariPool active reaching maxActive), and the management server stopped serving requests. Make PowerOperationTask a ManagedContextRunnable, like the poll task that submits it, so the managed context releases the connection when each run finishes. Fixes: #13382 --- .../PowerOperationTask.java | 5 ++- .../PowerOperationTaskTest.java | 43 +++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 server/src/test/java/org/apache/cloudstack/outofbandmanagement/PowerOperationTaskTest.java diff --git a/server/src/main/java/org/apache/cloudstack/outofbandmanagement/PowerOperationTask.java b/server/src/main/java/org/apache/cloudstack/outofbandmanagement/PowerOperationTask.java index 577164d4c0d6..51ddee451348 100644 --- a/server/src/main/java/org/apache/cloudstack/outofbandmanagement/PowerOperationTask.java +++ b/server/src/main/java/org/apache/cloudstack/outofbandmanagement/PowerOperationTask.java @@ -19,6 +19,7 @@ import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; @@ -27,7 +28,7 @@ import com.cloud.event.EventVO; import com.cloud.host.Host; -public class PowerOperationTask implements Runnable { +public class PowerOperationTask extends ManagedContextRunnable { protected Logger logger = LogManager.getLogger(getClass()); final private OutOfBandManagementService service; @@ -46,7 +47,7 @@ public String toString() { } @Override - public void run() { + protected void runInContext() { try { service.executePowerOperation(host, powerOperation, null); } catch (Exception e) { diff --git a/server/src/test/java/org/apache/cloudstack/outofbandmanagement/PowerOperationTaskTest.java b/server/src/test/java/org/apache/cloudstack/outofbandmanagement/PowerOperationTaskTest.java new file mode 100644 index 000000000000..f33f20e866ae --- /dev/null +++ b/server/src/test/java/org/apache/cloudstack/outofbandmanagement/PowerOperationTaskTest.java @@ -0,0 +1,43 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.outofbandmanagement; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import org.apache.cloudstack.managed.context.ManagedContextRunnable; +import org.junit.Assert; +import org.junit.Test; + +import com.cloud.host.Host; + +public class PowerOperationTaskTest { + + @Test + public void testTaskRunsWithinManagedContextAndExecutesOperation() { + OutOfBandManagementService service = mock(OutOfBandManagementService.class); + Host host = mock(Host.class); + PowerOperationTask task = new PowerOperationTask(service, host, OutOfBandManagement.PowerOperation.STATUS); + + Assert.assertTrue("Background task must run within a managed context so its DB connection is released to the pool", + task instanceof ManagedContextRunnable); + + task.run(); + + verify(service).executePowerOperation(host, OutOfBandManagement.PowerOperation.STATUS, null); + } +}