WebLogic 라이브러리 안정성 검증 로직 강화:
- jboss-logging/Guava 클래스 로드시충돌 점검 추가 - ReadinessController에 관련 체크 로직 반영
This commit is contained in:
@@ -5,6 +5,7 @@ import java.sql.SQLException;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@@ -12,19 +13,28 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.thymeleaf.spring5.SpringTemplateEngine;
|
||||
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
|
||||
/**
|
||||
* Readiness probe.
|
||||
*
|
||||
* <p>Distinct from {@link HealthCheckController} (liveness — servlet alive?).
|
||||
* This endpoint validates both EMS and Gateway datasources via JDBC
|
||||
* {@code Connection.isValid(timeout)}, and the Thymeleaf {@link SpringTemplateEngine}
|
||||
* configuration, to confirm the app is ready to serve real page requests.
|
||||
* {@code Connection.isValid(timeout)}, plus three libraries that WebLogic's
|
||||
* oracle_common bundles at a different version from this app (see weblogic.xml
|
||||
* {@code prefer-application-packages}): Thymeleaf's {@link SpringTemplateEngine}
|
||||
* (jackson), jboss-logging, and Guava.
|
||||
*
|
||||
* <p>The template-engine check exists because this controller bypasses view
|
||||
* resolution entirely (plain {@code @RestController} JSON) — a broken
|
||||
* {@code TemplateEngine.getConfiguration()} (e.g. classpath split causing
|
||||
* {@link java.util.ServiceConfigurationError} during dialect/module discovery)
|
||||
* previously left every real page returning 500 while this probe still reported 200.
|
||||
* <p>These exist because this controller bypasses view resolution entirely
|
||||
* (plain {@code @RestController} JSON) — a classpath split between the app's
|
||||
* copy and WebLogic's bundled copy of a preferred package can throw
|
||||
* {@link LinkageError}/{@link java.util.ServiceConfigurationError} only on the
|
||||
* real code paths that touch it, while this probe kept reporting 200. That
|
||||
* already happened once for jackson (Thymeleaf's dialect/module discovery
|
||||
* failed on every real page while /health/ready stayed green) — jboss-logging
|
||||
* and Guava carry the same risk (confirmed version mismatch against
|
||||
* oracle_common, not yet observed failing in production) so they get the same
|
||||
* kind of forced-touch check here.
|
||||
*
|
||||
* <p>HTTP 200 + JSON when all checks pass.
|
||||
* <p>HTTP 503 + JSON when any check fails — body still includes the per-component
|
||||
@@ -53,13 +63,18 @@ public class ReadinessController {
|
||||
String ems = check(portalDataSource);
|
||||
String gw = check(gatewayDataSource);
|
||||
String view = checkTemplateEngine();
|
||||
boolean ok = "UP".equals(ems) && "UP".equals(gw) && "UP".equals(view);
|
||||
String logging = checkJbossLogging();
|
||||
String guava = checkGuava();
|
||||
boolean ok = "UP".equals(ems) && "UP".equals(gw) && "UP".equals(view)
|
||||
&& "UP".equals(logging) && "UP".equals(guava);
|
||||
|
||||
String body = "{"
|
||||
+ "\"status\":\"" + (ok ? "UP" : "DOWN") + "\","
|
||||
+ "\"ems\":\"" + ems + "\","
|
||||
+ "\"gateway\":\"" + gw + "\","
|
||||
+ "\"view\":\"" + view + "\""
|
||||
+ "\"view\":\"" + view + "\","
|
||||
+ "\"logging\":\"" + logging + "\","
|
||||
+ "\"guava\":\"" + guava + "\""
|
||||
+ "}";
|
||||
|
||||
return ResponseEntity.status(ok ? 200 : 503)
|
||||
@@ -76,10 +91,39 @@ public class ReadinessController {
|
||||
templateEngine.getConfiguration();
|
||||
return "UP";
|
||||
} catch (Throwable t) {
|
||||
return down(t);
|
||||
}
|
||||
}
|
||||
|
||||
/** Forces jboss-logging's {@code Logger} + its bound provider (LogManager/JBoss/JUL
|
||||
* discovery) to load and actually run a log-level check, not just resolve the class. */
|
||||
private static String checkJbossLogging() {
|
||||
try {
|
||||
Logger log = Logger.getLogger(ReadinessController.class);
|
||||
log.isDebugEnabled();
|
||||
return "UP";
|
||||
} catch (Throwable t) {
|
||||
return down(t);
|
||||
}
|
||||
}
|
||||
|
||||
/** {@code Futures.immediateFuture} touches Guava's {@code util.concurrent} machinery
|
||||
* (AbstractFuture/InternalFutureFailureAccess) — the part backed by the separate
|
||||
* {@code failureaccess} jar, which is exactly where an app/WebLogic version mismatch
|
||||
* would split across classloaders. */
|
||||
private static String checkGuava() {
|
||||
try {
|
||||
Futures.immediateFuture(Boolean.TRUE).isDone();
|
||||
return "UP";
|
||||
} catch (Throwable t) {
|
||||
return down(t);
|
||||
}
|
||||
}
|
||||
|
||||
private static String down(Throwable t) {
|
||||
String msg = t.getMessage() == null ? t.getClass().getSimpleName() : t.getMessage();
|
||||
return "DOWN:" + msg.replace('"', '\'').replace('\n', ' ').replace('\r', ' ');
|
||||
}
|
||||
}
|
||||
|
||||
private static String check(DataSource ds) {
|
||||
if (ds == null) return "DOWN:NO_DATASOURCE";
|
||||
|
||||
Reference in New Issue
Block a user