Springboot - Spring Kafka - Lazy Container Factory initialization - java

With Spring JDBC Templates, you can initialize connections lazily with a simple flag. Is there a similar capability for Kafka Container Factories for Springboot 1.5.x / Spring Kafka 1.3.x deployments?
The best answer I have seen so far is to disable autoStart and manage the start on your own catching any exceptions that may occur during start up here - How to start spring application even if Kafka listener (spring-kafka) doesn't initialize
Is this the only way and is there any caveats when using KafkaListenerEndpointRegistry to self-manage the lifecycle of the container(s)?
Would Lazy annotation work with #KafkaListener, #Configuration class for Kafka configurations or similar component class? Shooting this question out there since there does not appear to be a documented approach for handling, while in parallel attempting some of these approaches in order to obtain feedback in parallel.
When using Springboot 1.5.x, how does this change (if any) with Springboot 2.1.x (or above) and compatible Spring Kafka version for those versions?

Lazy initialization of a listener container makes no sense. What would trigger the instantiation?
The KafkaTemplate lazily creates its producer on the first operation.
autoStartup and starting/stopping using the registry is the correct approach.
The version makes no difference.

Related

Continue Spring Kafka Startup even on Kafka Connection Failure

Is there a configuration I can use to instruct Spring to continue on startup and initialize the Beans even if Kafka connection failed?
I am using Spring Framework 5.2.3 and Spring Kafka 2.5.3.RELEASE.
If you need kafka beans for your application to work in every use case then continue with startup if there is no kafka connection makes no sense. Your application will not be able to do anything without kafka.
But if some parts of your application do not need kafka and you would like to use only those parts then you can either mark kafka related beans as lazy or make all beans lazy by default. In this case spring will create beans only when they are actually needed. And even if there is no kafka connection available parts of your app that do not need kafka will work.

Is Spring Data's #Transactional(Propagation.REQUIRES_NEW) supported in Vert.x?

From what I have read so far, Propagation.REQUIRES_NEW makes use of transaction suspension capabilities in most common Java EE containers (JBoss, Glassfish, etc.)
However, as we're running Spring Data inside Vert.x, which is container-less, I'd like to find a definitive answer as to whether REQUIRES_NEW is supported in this scenario, or if we will have to use another approach for this.
You can use Spring #Transactional annotations out of a JavaEE container. It will work well if you only use a database.
If you mix transactional components (a relational database and a message broker) then you need a transaction manager, which is often only available in JavaEE container.
I'm not a Spring or SpringBoot expert but I am pretty sure it's not difficult nowadays to add a transaction manager to a Spring/Tomcat project.
As for running Spring Data in Vert.x, it will work fine if you deploy this code in worker verticles. Check out the spring-worker sample in the vertx-examples repository on GitHub

Manually setting up Spring WebSocket STOMP support

I'm trying to set up a STOMP WS endpoint using spring-websocket and spring-messaging. I am trying to do this manually: no application context is involved at all, and certainly no dispatcher. My goal is to wire up the appropriate Spring components in code inside a ServletContextListener, then register the wired up components directly with the javax.websocket.server.ServerContainer in my JSR 356 compatible container (Tomcat 7). At first, I would like to get this working with the "simple" broker built into spring-messaging; secondly, I would like to implement my own "broker" to directly integrate with an in-process ActiveMQ using the VM transport. This would be in contrast to the STOMP relay which spring-messaging also provides.
The Spring documentation states (http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html):
"...Spring’s WebSocket support does not depend on Spring MVC. It is relatively simple to integrate a WebSocketHandler into other HTTP serving environments with the help of WebSocketHttpRequestHandler."
However, I am not finding it to be simple. Essentially, I started with:
public void contextInitialized(ServletContextEvent sce) {
ServerContainer websocketContainer = (ServerContainer) sce.getServletContext().getAttribute("javax.websocket.server.ServerContainer");
???
websocketContainer.addEndpoint(???);
}
And ended up with an incoherent mess of assorted spring-websocket and spring-messaging constructor invocations which do not compile and are certainly not worth reproducing here.
I realize this is a bit vague, this is because I'm a bit lost! Has anyone done something like this, or has some general guidance to contribute?
Did you try sample application - tests for the stock portfolio. (This link is at the very end of the spring documentation link).
It says
Demonstrates 3 approaches to testing a Spring STOMP over WebSocket application:
Server-side controller tests that load the actual Spring configuration (context sub-package)
Server-side controller tests that test one controller at a time without loading any Spring configuration (standalone sub-package)
End-to-end, full integration tests using an embedded Tomcat and a simple STOMP Java client (tomcat sub-package)
See the Javadoc of the respective tests for more details.
Second option is probably what you need.

Handle reconnection/retries using Lyra-style in Spring AMQP

I am using RabbitMQ covered with Spring AMQP abstraction.
So in essence I am using Spring AMQP.
I need to handle conneciton failures. It's fairly easy to achieve this using Lyra when you use raw RabbitMQ classes.
How do you achieve the same in Spring AMQP? I want my code to be unaware of any network problems.
I know Spring handles reconnections by default (in some way), but what I want is a Lyra-style configuration (be it in XML or wherever), so I can define timeout, max retries, backoff etc..
On the consuming side there is no way to configure that - the container will simply retry the connection on a fixed schedule; configurable by setting recoveryInterval in the SimpleMessageListenerContainer which defaults to 5 seconds. There's not much value in configuring a backoff for consumers.
On the publishing side, you can use spring-aop to wrap the RabbitTemplate (AmqpTemplate interface) in a MethodInterceptor that wraps the send*() calls in a RetryTemplate from spring-retry. The RetryTemplate can be configured with all sorts of options, including backoff policy etc.
If you need help with that, I can try to find some time to post a Gist.
EDIT:
Per the comment below - correct, the recoveryInterval is currently not available with the namespace (but you can still define the container as a <bean ... class="...SimpleMessageListenerContainer...>.
However, it was added a few weeks ago to the master branch (commit here). It is available in the 1.3.0.BUILD-SNAPSHOT.
Also, as a result of your question here, I have added a RetryTemplate option to the RabbitTemplate (pull request here). It should be merged soon. The release candidate for 1.3.0 (1.3.0.RC1) is due Friday and the 1.3.0 GA release will follow within a couple of weeks.

Unmanaged Threads Spring Quartz Websphere Hibernate

It appears that our implementation of using Quartz - JDBCJobStore along with Spring, Hibernate and Websphere is throwing unmanaged threads.
I have done some reading and found a tech article from IBM stating that the usage of Quartz with Spring will cause that. They make the suggestion of using CommnonJ to address this issue.
I have done some further research and the only examples I have seen so far all deal with the plan old JobStore that is not in a database.
So, I was wondering if anyone has an example of the solution for this issue.
Thanks
We have a working solution for this (two actually).
1) Alter the quartz source code to use a WorkManager daemon thread for the main scheduler thread. It works, but requires changing quarts. We didn't use this though since we didn't want maintain a hacked version of quartz. (That reminds me, I was going to submit this to the project but completely forgot)
2) Create a WorkManagerThreadPool to be used as the quartz threadpool. Implement the interface for the quartz ThreadPool, so that each task that is triggered within quartz is wrapped in a commonj Work object that will then be scheduled in the WorkManager. The key is that the WorkManager in the WorkManagerThreadPool has to be initialized before the scheduler is started, from a Java EE thread (such as servlet initialization). The WorkManagerThreadPool must then create a daemon thread which will handle all the scheduled tasks by creating and scheduling the new Work objects. This way, the scheduler (on its own thread) is passing the tasks to a managed thread (the Work daemon).
Not simple, and unfortunately I do not have code readily available to include.
Adding another answer to the thread, since i found a solution for this, finally.
My environment: WAS 8.5.5, Quartz 1.8.5, no Spring.
The problem i had was the (above stated) unmanaged thread causing a NamingException from ctx.lookup(myJndiUrl), that was instead correctly working in other application servers (JBoss, Weblogic); actually, Webpshere was firing an "incident" with the following message:
javax.naming.ConfigurationException: A JNDI operation on a "java:" name cannot be completed because the server runtime is not able to associate the operation's thread with any J2EE application component. This condition can occur when the JNDI client using the "java:" name is not executed on the thread of a server application request. Make sure that a J2EE application does not execute JNDI operations on "java:" names within static code blocks or in threads created by that J2EE application. Such code does not necessarily run on the thread of a server application request and therefore is not supported by JNDI operations on "java:" names.
The following steps solved the problem:
1) upgraded to quartz 1.8.6 (no code changes), just maven pom
2) added the following dep to classpath (in my case, EAR's /lib folder), to make the new WorkManagerThreadExecutor available
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-commonj</artifactId>
<version>1.8.6</version>
</dependency>
Note: in QTZ-113 or the official Quartz Documentation 1.x 2.x there's no mention on how to activate this fix.
3) added the following to quartz.properties ("wm/default" was the JNDI of the already configured DefaultWorkManager in my WAS 8.5.5, see Resources -> AsynchronousBeans -> WorkManagers in WAS console):
org.quartz.threadExecutor.class=org.quartz.custom.WorkManagerThreadExecutor
org.quartz.threadExecutor.workManagerName=wm/default
Note: right class is org.quartz.custom.WorkManagerThreadExecutor for quartz-scheduler-1.8.6 (tested), or org.quartz.commonj.WorkManagerThreadExecutor from 2.1.1 on (not tested, but verified within actual quartz-commonj's jars on maven's repos)
4) moved the JNDI lookup in the empty constructor of the quartz job (thanks to m_klovre's "Thread outside of the J2EE container"); that is, the constructor was being invoked by reflection (newInstance() method) from the very same J2EE context of my application, and had access to java:global namespace, while the execute(JobExecutionContext) method was still running in a poorer context, which was missing all of my application's EJBs
Hope this helps.
Ps. as a reference, you can find here an example of the quartz.properties file I was using above
Check this article:
http://www.ibm.com/developerworks/websphere/techjournal/0609_alcott/0609_alcott.html
basically, set the taskExecutor property on SchedulerFactoryBean to use a org.springframework.scheduling.commonj.WorkManager TaskExecutor which will use container managed threads.
Just a note: the above QUARTZ-708's link is not valid anymore.
This new issue (in a new Jira) seems to be addressing the problem: http://jira.terracotta.org/jira/browse/QTZ-113 (fixVersion = 1.8.6, 2.0.2)
I have recently encountered this problem. Practically you need:
Implement thread pool by delegating work to Websphere Work Manager. (Quartz provides only SimpleThreadPool that run jobs on unmanaged threads). Tell quartz to use this thread pool by org.quartz.threadPool.class property
Tell quartz to use WorkManagerThreadExecutor (or implement custom one) by org.quartz.threadExecutor.class property
A bit patience with cumbersome legacy web containers :)
Here is github demo of using Quartz with Websphere (and also Tomcat).
Hope it helps someone..
You can check the below JIRA link raised on quartz regarding this.
http://jira.opensymphony.com/browse/QUARTZ-708
This has the required WebSphereThreadPool implementation which can be used with the changes in quartz.properties as mentioned to meet your requirements. Hope this helps.
Regards,
Siva
You will have to use websphere's managed thread pools. You can do this via spring and commonj. CommonJ can has a task executor that will create managed threads. You can even use a reference to a jndi managed thread resource. You can then inject the commonj task executor into the Spring based Quartz SchedulerFactoryBean.
Please see http://open.bekk.no/boss/spring-scheduling-in-websphere/ and scroll to "Quartz with CommonJ" section for more details.
The proposal from PaoloC for WAS85 ans Quartz 1.8.6 also works on WAS80 (and Quartz 1.8.6) and does not need Spring. (In my setup Spring 2.5.5 is present, but not in use in that context.)
That way I was able to override SimpleJobFactory by my own variant, using an InjectionHelper to apply CDI on every newly created job. Injection works for both #EJB (with JNDI lookup of the annotated EJB remote business interface) and #Inject (with JNDI lookup of the CDI BeanManager using a new InitialContext first, and then using this newly fetched BM to lookup the CDI bean itself).
Thank you PaoloC for that answer! (I hope this text will appear as an "answer to PaoloC" and not as an answer to the main topic. Found no way to differentiate between these.)

Categories

Resources