From 9a720872c0fe5ecc52843d311d6da33d7648ea0a Mon Sep 17 00:00:00 2001 From: lekhrocks Date: Sun, 6 Sep 2026 11:54:23 +0530 Subject: [PATCH] fix(P4): replace per-call ObjectMapper with Spring-managed bean MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AgentRegistrar, HeartbeatSender, and LlmClient each created new ObjectMapper() on every call. Inject the Spring-managed ObjectMapper bean instead — thread-safe, properly configured with JavaTimeModule, and reused across the application lifecycle. --- .../syncflow/agent/client/AgentRegistrar.java | 21 +++++++++++-------- .../agent/client/HeartbeatSender.java | 17 ++++++++------- .../java/com/syncflow/api/ai/LlmClient.java | 4 ++-- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/syncflow-agent/src/main/java/com/syncflow/agent/client/AgentRegistrar.java b/syncflow-agent/src/main/java/com/syncflow/agent/client/AgentRegistrar.java index ae41e79..30351c1 100644 --- a/syncflow-agent/src/main/java/com/syncflow/agent/client/AgentRegistrar.java +++ b/syncflow-agent/src/main/java/com/syncflow/agent/client/AgentRegistrar.java @@ -1,5 +1,6 @@ package com.syncflow.agent.client; +import com.fasterxml.jackson.databind.ObjectMapper; import com.syncflow.agent.domain.AgentId; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,13 +21,16 @@ public class AgentRegistrar { private static final Logger log = LoggerFactory.getLogger(AgentRegistrar.class); private final HttpClient http; + private final ObjectMapper mapper; private final String controlPlaneUrl; private final String version; private AgentId agentId; public AgentRegistrar( + ObjectMapper objectMapper, @Value("${syncflow.agent.control-plane:http://localhost:8080}") String cpUrl, @Value("${syncflow.agent.version:0.1.0}") String version) { + this.mapper = objectMapper; this.controlPlaneUrl = cpUrl; this.version = version; this.http = HttpClient.newBuilder() @@ -36,14 +40,13 @@ public AgentRegistrar( public void register() { try { - var body = new com.fasterxml.jackson.databind.ObjectMapper() - .writeValueAsString(Map.of( - "version", version, - "capabilities", List.of("SNAPSHOT", "CDC", "SYNCHRONIZATION", "METADATA"), - "labels", Map.of("type", "standard"), - "environment", "customer", - "region", System.getenv().getOrDefault("REGION", "unknown"), - "hostname", java.net.InetAddress.getLocalHost().getHostName())); + var body = mapper.writeValueAsString(Map.of( + "version", version, + "capabilities", List.of("SNAPSHOT", "CDC", "SYNCHRONIZATION", "METADATA"), + "labels", Map.of("type", "standard"), + "environment", "customer", + "region", System.getenv().getOrDefault("REGION", "unknown"), + "hostname", java.net.InetAddress.getLocalHost().getHostName())); var req = HttpRequest.newBuilder() .uri(URI.create(controlPlaneUrl + "/api/agents/register")) @@ -54,7 +57,7 @@ public void register() { var resp = http.send(req, HttpResponse.BodyHandlers.ofString()); if (resp.statusCode() == 200) { - var json = new com.fasterxml.jackson.databind.ObjectMapper().readTree(resp.body()); + var json = mapper.readTree(resp.body()); this.agentId = new AgentId(json.get("id").get("value").asText()); log.info("Agent registered: {}", agentId); } else { diff --git a/syncflow-agent/src/main/java/com/syncflow/agent/client/HeartbeatSender.java b/syncflow-agent/src/main/java/com/syncflow/agent/client/HeartbeatSender.java index 4d0b3e9..dca5888 100644 --- a/syncflow-agent/src/main/java/com/syncflow/agent/client/HeartbeatSender.java +++ b/syncflow-agent/src/main/java/com/syncflow/agent/client/HeartbeatSender.java @@ -1,5 +1,6 @@ package com.syncflow.agent.client; +import com.fasterxml.jackson.databind.ObjectMapper; import com.syncflow.agent.domain.HardwareMetrics; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,13 +22,16 @@ public class HeartbeatSender { private static final Logger log = LoggerFactory.getLogger(HeartbeatSender.class); private final HttpClient http; + private final ObjectMapper mapper; private final String controlPlaneUrl; private final AgentRegistrar registrar; private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); public HeartbeatSender(AgentRegistrar registrar, + ObjectMapper objectMapper, @org.springframework.beans.factory.annotation.Value("${syncflow.agent.control-plane:http://localhost:8080}") String cpUrl) { this.registrar = registrar; + this.mapper = objectMapper; this.controlPlaneUrl = cpUrl; this.http = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(5)).build(); } @@ -48,13 +52,12 @@ private void send() { mem.totalMemory(), 0, 0, 0, 0, 0); try { - var body = new com.fasterxml.jackson.databind.ObjectMapper() - .writeValueAsString(Map.of( - "agentId", agentId.value(), - "cpuPercent", hw.cpuPercent(), - "memoryUsed", hw.memoryUsed(), - "memoryTotal", hw.memoryTotal(), - "runningJobs", hw.runningJobs())); + var body = mapper.writeValueAsString(Map.of( + "agentId", agentId.value(), + "cpuPercent", hw.cpuPercent(), + "memoryUsed", hw.memoryUsed(), + "memoryTotal", hw.memoryTotal(), + "runningJobs", hw.runningJobs())); var req = HttpRequest.newBuilder() .uri(URI.create(controlPlaneUrl + "/api/agents/heartbeat")) diff --git a/syncflow-api/src/main/java/com/syncflow/api/ai/LlmClient.java b/syncflow-api/src/main/java/com/syncflow/api/ai/LlmClient.java index 62c7fdd..ab6f2ad 100644 --- a/syncflow-api/src/main/java/com/syncflow/api/ai/LlmClient.java +++ b/syncflow-api/src/main/java/com/syncflow/api/ai/LlmClient.java @@ -18,12 +18,12 @@ public class LlmClient { private final HttpClient http; private final ObjectMapper mapper; - public LlmClient(AiProperties props) { + public LlmClient(AiProperties props, ObjectMapper objectMapper) { this.props = props; this.http = HttpClient.newBuilder() .connectTimeout(Duration.ofSeconds(30)) .build(); - this.mapper = new ObjectMapper(); + this.mapper = objectMapper; } public String call(String prompt, String sessionId) {