fix(velocity): fail loud when global macro library load fails (#35601)#35768
fix(velocity): fail loud when global macro library load fails (#35601)#35768dsolistorres wants to merge 2 commits into
Conversation
VelocimacroFactory silently swallowed ResourceNotFoundException when loading velocimacro.library files at engine init, allowing init to "succeed" with no global macros registered. After K8s pod restarts with transient I/O errors (notably on EFS-backed volumes), #renderMarks and #editContentlet rendered as literal text on every page until the JVM was restarted. The catch now logs the failed library name at ERROR and tracks failures so init can throw VelocityException when any required library failed. A new flag velocimacro.library.fail-on-missing (default true) lets self-hosted operators preserve the legacy silent-warn behavior if they intentionally configure optional libraries. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Claude finished @dsolistorres's task in 2m 48s —— View job dotCMS Backend Review
Result✅ All four sub-agents (Security, Database, Java Standards, REST) returned The earlier 🟡 Medium diamond-operator nit was already addressed in commit
|
|
✅ dotCMS Backend Review: no issues found. |
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| # When true (default), engine init throws VelocityException if any velocimacro.library | ||
| # file fails to load — prevents silent macro-rendering failures on pod restart (issue #35601). | ||
| # Set to false only if you intentionally configure optional/missing library files. | ||
| velocimacro.library.fail-on-missing=true |
There was a problem hiding this comment.
This is a feature flag and should use `Config.getBooleanProperty("XXXX")``
| "Velocimacro libraries loaded: " + loadedLibraries | ||
| + " ; failed: " + failedLibraries); | ||
|
|
||
| if (failOnMissing && !failedLibraries.isEmpty()) |
There was a problem hiding this comment.
This is a breaking change - who knows how many dotCMS customers would fail this and their sites stop rendering when we updated them? Before we change default behavior, we need to make sure we understand what we're doing, if it could result in breakage and and gate it properly. This needs to default to off.
Summary
Closes #35601 (follow-up implementation from spike #35329).
VelocimacroFactorysilently swallowedResourceNotFoundExceptionwhen loading the configuredvelocimacro.libraryfiles at engine init, allowingengine.init()to return successfully with no global macros registered. After K8s pod restarts with transient I/O errors (notably on EFS-backed volumes),#renderMarks($element)and#editContentletrendered as literal text on every public page until the JVM was restarted.Changes
VelocimacroFactory.initVelocimacro()— track loaded/failed libraries through the load loop. TheResourceNotFoundExceptioncatch now logs atERRORwith the failed library file name. After the loop, anINFOsummary line lists loaded and failed libraries (greppable for ops). When any library failed, throwVelocityExceptionwith an actionable message naming the failed library and the opt-out flag.velocimacro.library.fail-on-missing(defaulttrue) preserves the legacy silent-warn behavior for self-hosted operators who intentionally configure optional libraries.RuntimeConstants.VM_LIBRARY_FAIL_ON_MISSING— new constant.system.properties— explicit default with a one-line comment.VelocimacroFactoryTest(new) — three unit tests coveringfail-on-missing=true,fail-on-missing=false, and the default.Why this is enough
engine.init()throws →VelocityUtil.getEngine()(VelocityUtil.java:65) rethrows asDotRuntimeException→ propagates out ofInitServlet.init()at line 199 →dotcms.started.upis never set → existingServletContainerHealthCheckalready gates/readyzon that flag → K8s readiness probe fails → no traffic routed → eventual pod restart gives EFS time to settle.Companion ticket #35602 (
VelocityHealthCheck) is still valuable as defense-in-depth — it catches the opt-out case (fail-on-missing=false) and any future post-init macro corruption that this flag wouldn't see.Test plan
VelocimacroFactoryTest— 3/3 pass (fail-on-missing=truethrows,falsesucceeds, default throws). Runtime ERROR/INFO log lines verified in test output.VelocityUtilTest— 20/20 pass (no regression).bogus-smoke-test.vmtovelocimacro.library, ranjust dev-run. Observed:ERROR runtime.VelocimacroFactory - Velocimacro : VM library not found : bogus-smoke-test.vm : ...INFO runtime.VelocimacroFactory - Velocimacro libraries loaded: [VM_global_library.vm, dotCMS_library.vm, dotCMS_library_ext.vm] ; failed: [bogus-smoke-test.vm]VelocityException: Velocimacro : required VM libraries failed to load: [bogus-smoke-test.vm]. Set velocimacro.library.fail-on-missing=false to allow startup with missing libraries.InitServlet.init(InitServlet.java:199)and rethrow asDotRuntimeExceptionInitServlet init Completedabsent from log (init aborted beforedotcms.started.up=true)/dotmgt/readyzreturns HTTP 503/dotmgt/livezreturns HTTP 503🤖 Generated with Claude Code