Loading src/policy/src/main/java/org/etsi/tfs/policy/policy/CommonPolicyServiceImpl.java +33 −6 Changes for src/policy/src/main/java/org/etsi/tfs/policy/policy/CommonPolicyServiceImpl.java: 33 added lines, 6 removed lines. Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; // import java.util.Random; import java.util.concurrent.ConcurrentHashMap; import org.eclipse.microprofile.config.inject.ConfigProperty; Loading Loading @@ -74,11 +75,25 @@ public class CommonPolicyServiceImpl { private static final ObjectMapper ALARM_NOTIFICATION_JSON = new ObjectMapper(); // Shared, reusable client (HttpClient is thread-safe and meant to be reused, // not created per-request). Short connect timeout: this is an in-cluster // call and should fail fast rather than hang if OpticalController is down. private static final HttpClient ALARM_NOTIFICATION_HTTP_CLIENT = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(3)).build(); // Deliberately NOT a shared, reused-forever HttpClient: a single // long-lived client keeps HTTP/1.1 connections open in its own internal // pool, and if OpticalController's backing pod is ever replaced (a // redeploy, a restart) while one of those connections is still open, it // can stay pinned to the old, now-dead pod for the rest of this JVM's // life -- every send on it still completes and reports a real HTTP 200 // from this client's own point of view, but it never actually reaches // the current pod, so this logs "forwarded to OpticalController" // indefinitely while OpticalController silently receives nothing at // all (observed in practice). Building a fresh client per call means a // fresh connection -- and fresh Service routing -- every single time, // which fully closes that failure mode. The extra per-call connection // setup is trivial next to the alarm-delivery reliability it buys, at // this call's actual frequency (once per KPI sample, roughly every // 10s). Short connect timeout: this is an in-cluster call and should // fail fast rather than hang if OpticalController is down. private static HttpClient newAlarmNotificationHttpClient() { return HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(3)).build(); } // private static final int POLICY_EVALUATION_TIMEOUT = 5; // private static final int ACCEPTABLE_NUMBER_OF_ALARMS = 3; Loading Loading @@ -265,10 +280,21 @@ public class CommonPolicyServiceImpl { .POST(BodyPublishers.ofString(json)) .build(); ALARM_NOTIFICATION_HTTP_CLIENT // Held in a local variable and explicitly referenced from both // callbacks below (see the two Objects.requireNonNull(client, ...) // calls) so this client stays strongly reachable for as long as // the async request is in flight. A per-call HttpClient with // nothing else referencing it would otherwise be eligible for // garbage collection the moment sendAsync() returns (it returns // immediately; the actual request runs on the client's own // internal executor) -- if that happened mid-request, the // request could be silently abandoned instead of completing. HttpClient client = newAlarmNotificationHttpClient(); client .sendAsync(request, BodyHandlers.ofString()) .thenAccept( response -> { Objects.requireNonNull(client, "keep client reachable until response arrives"); if (response.statusCode() >= 200 && response.statusCode() < 300) { LOGGER.infof( "Alarm notification for service %s forwarded to OpticalController (HTTP %d)", Loading @@ -281,6 +307,7 @@ public class CommonPolicyServiceImpl { }) .exceptionally( ex -> { Objects.requireNonNull(client, "keep client reachable until failure is reported"); LOGGER.warnf( "Failed to forward alarm notification for service %s to OpticalController: %s", serviceId, ex.getMessage()); Loading src/webui/service/templates/main/home.html +1 −1 Changes for src/webui/service/templates/main/home.html: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -17,7 +17,7 @@ {% extends 'base.html' %} {% block content %} <h2>ETSI TeraFlowSDN Controller (Optical SDN Controller)</h2> <h2>ETSI TeraFlowSDN Controller</h2> <style> #topology { border: 1px solid #b5b5b5; Loading Loading
src/policy/src/main/java/org/etsi/tfs/policy/policy/CommonPolicyServiceImpl.java +33 −6 Changes for src/policy/src/main/java/org/etsi/tfs/policy/policy/CommonPolicyServiceImpl.java: 33 added lines, 6 removed lines. Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; // import java.util.Random; import java.util.concurrent.ConcurrentHashMap; import org.eclipse.microprofile.config.inject.ConfigProperty; Loading Loading @@ -74,11 +75,25 @@ public class CommonPolicyServiceImpl { private static final ObjectMapper ALARM_NOTIFICATION_JSON = new ObjectMapper(); // Shared, reusable client (HttpClient is thread-safe and meant to be reused, // not created per-request). Short connect timeout: this is an in-cluster // call and should fail fast rather than hang if OpticalController is down. private static final HttpClient ALARM_NOTIFICATION_HTTP_CLIENT = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(3)).build(); // Deliberately NOT a shared, reused-forever HttpClient: a single // long-lived client keeps HTTP/1.1 connections open in its own internal // pool, and if OpticalController's backing pod is ever replaced (a // redeploy, a restart) while one of those connections is still open, it // can stay pinned to the old, now-dead pod for the rest of this JVM's // life -- every send on it still completes and reports a real HTTP 200 // from this client's own point of view, but it never actually reaches // the current pod, so this logs "forwarded to OpticalController" // indefinitely while OpticalController silently receives nothing at // all (observed in practice). Building a fresh client per call means a // fresh connection -- and fresh Service routing -- every single time, // which fully closes that failure mode. The extra per-call connection // setup is trivial next to the alarm-delivery reliability it buys, at // this call's actual frequency (once per KPI sample, roughly every // 10s). Short connect timeout: this is an in-cluster call and should // fail fast rather than hang if OpticalController is down. private static HttpClient newAlarmNotificationHttpClient() { return HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(3)).build(); } // private static final int POLICY_EVALUATION_TIMEOUT = 5; // private static final int ACCEPTABLE_NUMBER_OF_ALARMS = 3; Loading Loading @@ -265,10 +280,21 @@ public class CommonPolicyServiceImpl { .POST(BodyPublishers.ofString(json)) .build(); ALARM_NOTIFICATION_HTTP_CLIENT // Held in a local variable and explicitly referenced from both // callbacks below (see the two Objects.requireNonNull(client, ...) // calls) so this client stays strongly reachable for as long as // the async request is in flight. A per-call HttpClient with // nothing else referencing it would otherwise be eligible for // garbage collection the moment sendAsync() returns (it returns // immediately; the actual request runs on the client's own // internal executor) -- if that happened mid-request, the // request could be silently abandoned instead of completing. HttpClient client = newAlarmNotificationHttpClient(); client .sendAsync(request, BodyHandlers.ofString()) .thenAccept( response -> { Objects.requireNonNull(client, "keep client reachable until response arrives"); if (response.statusCode() >= 200 && response.statusCode() < 300) { LOGGER.infof( "Alarm notification for service %s forwarded to OpticalController (HTTP %d)", Loading @@ -281,6 +307,7 @@ public class CommonPolicyServiceImpl { }) .exceptionally( ex -> { Objects.requireNonNull(client, "keep client reachable until failure is reported"); LOGGER.warnf( "Failed to forward alarm notification for service %s to OpticalController: %s", serviceId, ex.getMessage()); Loading
src/webui/service/templates/main/home.html +1 −1 Changes for src/webui/service/templates/main/home.html: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -17,7 +17,7 @@ {% extends 'base.html' %} {% block content %} <h2>ETSI TeraFlowSDN Controller (Optical SDN Controller)</h2> <h2>ETSI TeraFlowSDN Controller</h2> <style> #topology { border: 1px solid #b5b5b5; Loading