[
https://issues.apache.org/jira/browse/CAMEL-24351?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Henrik updated CAMEL-24351:
---------------------------
Description:
{code:json}
{"status":404,"error":"Not Found","path":"/myroute"}
{code}
Camel logs nothing for these requests because no route is invoked, and the app
looks healthy: startup shows \{{Started myroute (rest://get:/myroute)}},
non-HTTP routes work, health probes stay green. Whether an instance is affected
is decided at startup and fixed for its lifetime, so restarts appear to fix it
at random.
h3. Cause
{\{SpringBootPlatformHttpAutoConfiguration}} declares the mapping bean \{{@Bean
@Lazy}}. \{{CamelRequestHandlerMapping}} registers itself as a
\{{PlatformHttpListener}} in its constructor, and
\{{PlatformHttpComponent.addHttpEndpoint()}} notifies only listeners that
already exist. A lazy bean is created on first demand, which is not ordered
against CamelContext startup: if Camel starts before anything resolves
\{{HandlerMapping}} beans, all endpoints are registered before the mapping
exists and its registry stays empty forever. It is silent because
\{{addPlatformHttpListener()}} does not replay \{{getHttpEndpoints()}} to a new
listener, and \{{addHttpEndpoint()}} logs listener exceptions at WARN only.
h3. Why 4.21.0
Eager singletons are created in \{{preInstantiateSingletons()}}, always before
\{{finishRefresh()}} starts Camel, so the listener could not miss a
registration.
||Version||Annotation||Instantiation||
|4.18.3|none|eager|
|4.20.0|@DependsOn|eager|
|4.21.0|@Lazy|lazy|
Verified from the constant pool of the released class in each starter jar.
\{{@Lazy}} arrived in commit 264db4c12e0 ("Fix compilation error in
camel-aws-s3 (#1783)"), which replaced an \{{ObjectProvider<CamelContext>}}
parameter, used to defer the lookup and avoid a circular dependency, with
direct injection plus \{{@Lazy}}.
Applications with a separate management port are not affected: the management
child context initialises its DispatcherServlet during startup, which
instantiates the parent's mapping before Camel starts. Deterministic check:
\{{getBeanDefinition("platformHttpEngineRequestMapping").isLazyInit()}}.
h3. Fix
Drop \{{@Lazy}} and resolve the CamelContext from an \{{ObjectProvider}} inside
the method, restoring eager instantiation while keeping the circular dependency
avoidance:
{code:java}
@Bean
public CamelRequestHandlerMapping platformHttpEngineRequestMapping(
PlatformHttpEngine engine, ObjectProvider<CamelContext> camelContextProvider) {
CamelContext camelContext = camelContextProvider.getObject();
PlatformHttpComponent component = camelContext.getComponent("platform-http",
PlatformHttpComponent.class);
return new CamelRequestHandlerMapping(component, engine);
}
{code}
h3. Workaround
{\{spring.mvc.servlet.load-on-startup=1}}: Tomcat's
\{{performDeferredLoadOnStartup()}} runs inside \{{onRefresh()}}, before the
\{{ContextRefreshedEvent}} that starts Camel.
PR: [https://github.com/apache/camel-spring-boot/pull/1874]
was:
`@Lazy` on the mapping bean means it is created on first demand, which is
unordered against CamelContext startup. `CamelRequestHandlerMapping` registers
itself as a `PlatformHttpListener` from its constructor, and `addHttpEndpoint`
notifies only listeners existing at that moment - so if Camel starts first, the
mapping receives no callback for any endpoint and its registry stays empty.
Requests then get Spring's `BasicErrorController` 404, including the correct
path, which is what makes it confusing to diagnose.
PR: [https://github.com/apache/camel-spring-boot/pull/1874]
> camel-platform-http-starter: CamelRequestHandlerMapping is @Lazy, so every
> platform-http endpoint can silently return 404
> ---------------------------------------------------------------------------------------------------------------------------
>
> Key: CAMEL-24351
> URL: https://issues.apache.org/jira/browse/CAMEL-24351
> Project: Camel
> Issue Type: Bug
> Components: camel-platform-http
> Affects Versions: 4.21.0
> Reporter: Henrik
> Priority: Major
> Labels: regression, spring-boot
> Attachments:
> 0001-CAMEL-24351-camel-platform-http-starter-the-request-.patch
>
>
> {code:json}
> {"status":404,"error":"Not Found","path":"/myroute"}
> {code}
> Camel logs nothing for these requests because no route is invoked, and the
> app looks healthy: startup shows \{{Started myroute (rest://get:/myroute)}},
> non-HTTP routes work, health probes stay green. Whether an instance is
> affected is decided at startup and fixed for its lifetime, so restarts appear
> to fix it at random.
> h3. Cause
> {\{SpringBootPlatformHttpAutoConfiguration}} declares the mapping bean
> \{{@Bean @Lazy}}. \{{CamelRequestHandlerMapping}} registers itself as a
> \{{PlatformHttpListener}} in its constructor, and
> \{{PlatformHttpComponent.addHttpEndpoint()}} notifies only listeners that
> already exist. A lazy bean is created on first demand, which is not ordered
> against CamelContext startup: if Camel starts before anything resolves
> \{{HandlerMapping}} beans, all endpoints are registered before the mapping
> exists and its registry stays empty forever. It is silent because
> \{{addPlatformHttpListener()}} does not replay \{{getHttpEndpoints()}} to a
> new listener, and \{{addHttpEndpoint()}} logs listener exceptions at WARN
> only.
> h3. Why 4.21.0
> Eager singletons are created in \{{preInstantiateSingletons()}}, always
> before \{{finishRefresh()}} starts Camel, so the listener could not miss a
> registration.
> ||Version||Annotation||Instantiation||
> |4.18.3|none|eager|
> |4.20.0|@DependsOn|eager|
> |4.21.0|@Lazy|lazy|
> Verified from the constant pool of the released class in each starter jar.
> \{{@Lazy}} arrived in commit 264db4c12e0 ("Fix compilation error in
> camel-aws-s3 (#1783)"), which replaced an \{{ObjectProvider<CamelContext>}}
> parameter, used to defer the lookup and avoid a circular dependency, with
> direct injection plus \{{@Lazy}}.
> Applications with a separate management port are not affected: the management
> child context initialises its DispatcherServlet during startup, which
> instantiates the parent's mapping before Camel starts. Deterministic check:
> \{{getBeanDefinition("platformHttpEngineRequestMapping").isLazyInit()}}.
> h3. Fix
> Drop \{{@Lazy}} and resolve the CamelContext from an \{{ObjectProvider}}
> inside the method, restoring eager instantiation while keeping the circular
> dependency avoidance:
> {code:java}
> @Bean
> public CamelRequestHandlerMapping platformHttpEngineRequestMapping(
> PlatformHttpEngine engine, ObjectProvider<CamelContext> camelContextProvider)
> {
> CamelContext camelContext = camelContextProvider.getObject();
> PlatformHttpComponent component = camelContext.getComponent("platform-http",
> PlatformHttpComponent.class);
> return new CamelRequestHandlerMapping(component, engine);
> }
> {code}
> h3. Workaround
> {\{spring.mvc.servlet.load-on-startup=1}}: Tomcat's
> \{{performDeferredLoadOnStartup()}} runs inside \{{onRefresh()}}, before the
> \{{ContextRefreshedEvent}} that starts Camel.
> PR: [https://github.com/apache/camel-spring-boot/pull/1874]
--
This message was sent by Atlassian Jira
(v8.20.10#820010)