fix: break circular dependency between runtimeOrchestrator and containerLogForwarder
All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 1m33s
CI / docker (push) Successful in 1m11s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Successful in 40s
SonarQube / sonarqube (push) Successful in 3m34s

Extract DockerClient creation into a standalone bean so both
runtimeOrchestrator and containerLogForwarder depend on it directly
instead of on each other. DockerRuntimeOrchestrator now receives
DockerClient via constructor instead of creating it in @PostConstruct.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-15 00:06:40 +02:00
parent 9c912fe694
commit bf2d07f3ba
2 changed files with 41 additions and 29 deletions

View File

@@ -12,10 +12,6 @@ import com.github.dockerjava.api.model.HealthCheck;
import com.github.dockerjava.api.model.HostConfig; import com.github.dockerjava.api.model.HostConfig;
import com.github.dockerjava.api.model.RestartPolicy; import com.github.dockerjava.api.model.RestartPolicy;
import com.github.dockerjava.api.model.Volume; import com.github.dockerjava.api.model.Volume;
import com.github.dockerjava.core.DefaultDockerClientConfig;
import com.github.dockerjava.core.DockerClientImpl;
import com.github.dockerjava.zerodep.ZerodepDockerHttpClient;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy; import jakarta.annotation.PreDestroy;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -29,24 +25,16 @@ import java.util.stream.Stream;
public class DockerRuntimeOrchestrator implements RuntimeOrchestrator { public class DockerRuntimeOrchestrator implements RuntimeOrchestrator {
private static final Logger log = LoggerFactory.getLogger(DockerRuntimeOrchestrator.class); private static final Logger log = LoggerFactory.getLogger(DockerRuntimeOrchestrator.class);
private DockerClient dockerClient; private final DockerClient dockerClient;
private ContainerLogForwarder logForwarder; private ContainerLogForwarder logForwarder;
public void setLogForwarder(ContainerLogForwarder logForwarder) { public DockerRuntimeOrchestrator(DockerClient dockerClient) {
this.logForwarder = logForwarder; this.dockerClient = dockerClient;
} }
@PostConstruct public void setLogForwarder(ContainerLogForwarder logForwarder) {
public void init() { this.logForwarder = logForwarder;
var config = DefaultDockerClientConfig.createDefaultConfigBuilder()
.withDockerHost("unix:///var/run/docker.sock")
.build();
var httpClient = new ZerodepDockerHttpClient.Builder()
.dockerHost(config.getDockerHost())
.build();
dockerClient = DockerClientImpl.getInstance(config, httpClient);
log.info("Docker client initialized, host: {}", config.getDockerHost());
} }
@PreDestroy @PreDestroy

View File

@@ -4,8 +4,13 @@ import com.cameleer3.server.app.search.ClickHouseLogStore;
import com.cameleer3.server.app.storage.PostgresDeploymentRepository; import com.cameleer3.server.app.storage.PostgresDeploymentRepository;
import com.cameleer3.server.core.runtime.DeploymentRepository; import com.cameleer3.server.core.runtime.DeploymentRepository;
import com.cameleer3.server.core.runtime.RuntimeOrchestrator; import com.cameleer3.server.core.runtime.RuntimeOrchestrator;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.core.DefaultDockerClientConfig;
import com.github.dockerjava.core.DockerClientImpl;
import com.github.dockerjava.zerodep.ZerodepDockerHttpClient;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -17,13 +22,29 @@ public class RuntimeOrchestratorAutoConfig {
private static final Logger log = LoggerFactory.getLogger(RuntimeOrchestratorAutoConfig.class); private static final Logger log = LoggerFactory.getLogger(RuntimeOrchestratorAutoConfig.class);
@Bean
public DockerClient dockerClient() {
if (!Files.exists(Path.of("/var/run/docker.sock"))) {
return null;
}
var config = DefaultDockerClientConfig.createDefaultConfigBuilder()
.withDockerHost("unix:///var/run/docker.sock")
.build();
var httpClient = new ZerodepDockerHttpClient.Builder()
.dockerHost(config.getDockerHost())
.build();
DockerClient client = DockerClientImpl.getInstance(config, httpClient);
log.info("Docker client initialized, host: {}", config.getDockerHost());
return client;
}
@Bean @Bean
public RuntimeOrchestrator runtimeOrchestrator( public RuntimeOrchestrator runtimeOrchestrator(
@org.springframework.beans.factory.annotation.Autowired(required = false) @Autowired(required = false) DockerClient dockerClient,
ContainerLogForwarder logForwarder) { @Autowired(required = false) ContainerLogForwarder logForwarder) {
if (Files.exists(Path.of("/var/run/docker.sock"))) { if (dockerClient != null) {
log.info("Docker socket detected - enabling Docker runtime orchestrator"); log.info("Docker socket detected - enabling Docker runtime orchestrator");
DockerRuntimeOrchestrator orchestrator = new DockerRuntimeOrchestrator(); DockerRuntimeOrchestrator orchestrator = new DockerRuntimeOrchestrator(dockerClient);
if (logForwarder != null) { if (logForwarder != null) {
orchestrator.setLogForwarder(logForwarder); orchestrator.setLogForwarder(logForwarder);
} }
@@ -34,27 +55,30 @@ public class RuntimeOrchestratorAutoConfig {
} }
@Bean @Bean
public DockerNetworkManager dockerNetworkManager(RuntimeOrchestrator orchestrator) { public DockerNetworkManager dockerNetworkManager(
if (orchestrator instanceof DockerRuntimeOrchestrator docker) { @Autowired(required = false) DockerClient dockerClient) {
return new DockerNetworkManager(docker.getDockerClient()); if (dockerClient != null) {
return new DockerNetworkManager(dockerClient);
} }
return null; return null;
} }
@Bean @Bean
public DockerEventMonitor dockerEventMonitor(RuntimeOrchestrator orchestrator, public DockerEventMonitor dockerEventMonitor(RuntimeOrchestrator orchestrator,
@Autowired(required = false) DockerClient dockerClient,
DeploymentRepository deploymentRepository) { DeploymentRepository deploymentRepository) {
if (orchestrator instanceof DockerRuntimeOrchestrator docker) { if (orchestrator instanceof DockerRuntimeOrchestrator docker && dockerClient != null) {
return new DockerEventMonitor(docker, (PostgresDeploymentRepository) deploymentRepository); return new DockerEventMonitor(docker, (PostgresDeploymentRepository) deploymentRepository);
} }
return null; return null;
} }
@Bean @Bean
public ContainerLogForwarder containerLogForwarder(RuntimeOrchestrator orchestrator, public ContainerLogForwarder containerLogForwarder(
ClickHouseLogStore logStore) { @Autowired(required = false) DockerClient dockerClient,
if (orchestrator instanceof DockerRuntimeOrchestrator docker) { ClickHouseLogStore logStore) {
return new ContainerLogForwarder(docker.getDockerClient(), logStore); if (dockerClient != null) {
return new ContainerLogForwarder(dockerClient, logStore);
} }
return null; return null;
} }