Spring Batch & Azure SQL Server: Could not get JDBC Connection - spring

We are in the process of moving to Azure SQL Server from Oracle DB for our Spring Batch application.
I am getting the following error intermittently
ERROR : 01.03.2022:1458 (40.269) [[]main] CommandLineJobRunner: Job
Terminated in error: Error creating bean with name 'dateStoreList':
Cannot resolve reference to bean 'jobRepository' while setting bean
property 'jobRepository'; nested exception is
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'jobRepository': Invocation of init method
failed; nested exception is
org.springframework.jdbc.support.MetaDataAccessException: Could not
get Connection for extracting meta data; nested exception is
org.springframework.jdbc.CannotGetJdbcConnectionException: Could not
get JDBC Connection; nested exception is
org.apache.commons.dbcp.SQLNestedException: Cannot create
PoolableConnectionFactory (The TCP/IP connection to the host
sqlsrv-01.database.windows.net, port 1433 has failed. Error:
"sqlsrv-01.database.windows.net. Verify the connection properties.
Make sure that an instance of SQL Server is running on the host and
accepting TCP/IP connections at the port. Make sure that TCP
connections to the port are not blocked by a firewall.".)
Data Source:
<!-- Connection Pooled DATA SOURCE -->
<beanid="dataSource"class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close">
<propertyname="driverClassName"value="${jdbc.driverClassName}"/>
<propertyname="url"value="${jdbc.url}"/>
<propertyname="connectionProperties"value="sendStringParametersAsUnicode=false;"/>
<propertyname="username"value="${jdbc.username}"/>
<propertyname="password"value="${jdbc.password}"/>
<property name="initialSize" value="2" />
<property name="maxActive" value="20" />
<property name="maxIdle" value="1" />
<property name="validationQuery" value="SELECT 1"/>
<propertyname="testOnBorrow"value="false"/>
<propertyname="testWhileIdle"value="true"/>
<propertyname="timeBetweenEvictionRunsMillis"value="1200000"/>
<propertyname="minEvictableIdleTimeMillis"value="3000000"/>
<propertyname="numTestsPerEvictionRun"value="10"/>
<propertyname="poolPreparedStatements"value="true"/>
<propertyname="defaultAutoCommit"value="false"/>
</bean>
How do I enable retry at the spring batch application level to handle any database intermittent failure and recovery automatically?

According to this StackOverflow answer, as a temporary solution, you can add ?autoReconnect=true to your JDBC URL. I wonder, though, if this is a bandaid solution, and if there is a worse issue present. Take a look at this Microsoft article about dropped connections. Are your connections getting stale and being dropped?

Related

Using DefaultMessageListenerContainer to connect to WebSphere MQ throws "Connection closed" repeatedly

I need to connect from a web application running on a WebSphere AS 6.1 application server to a remote WebSphere MQ on z/OS queue. On WebSphere AS, I configured both QueueConnectionFactory and Queue (an object containing a part of the remote queue data), with most of the settings set to their default values - I just needed to set queue name, channel, host, port, and transport type which is CLIENT. I inject them in the following Spring 3.2 configuration using JNDI lookup:
<jee:jndi-lookup id="destination" jndi-name="MyMQQueue" expected-type="javax.jms.Queue" />
<jee:jndi-lookup id="targetConnectionFactory" jndi-name="MyMQQCF" expected-type="javax.jms.QueueConnectionFactory" />
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"
p:connectionFactory-ref="targetConnectionFactory"
p:defaultDestination-ref="destination" />
<bean id="simpleMessageListener" class="my.own.SimpleMessageListener"/>
<bean id="msgListenerContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="targetConnectionFactory" />
<property name="destination" ref="destination" />
<property name="messageListener" ref="simpleMessageListener" />
<property name="taskExecutor" ref="managedThreadsTaskExecutor" />
<property name="receiveTimeout" value="5000" />
<property name="recoveryInterval" value="5000" />
</bean>
<bean id="managedThreadsTaskExecutor" class="org.springframework.scheduling.commonj.WorkManagerTaskExecutor">
<property name="workManagerName" value="wm/default" />
</bean>
JmsTemplate sends and receives (synchronously) messages correctly. DefaultMessageListenerContainer, an asynchronous message receiver, reads some (previously sent) messages off the MQ queue during WebSphere AS start, but chokes soon afterwards, and begins to throw repeatedly "connection closed" exception. On each such occasion it notifies me that
DefaultMessag W org.springframework.jms.listener.DefaultMessageListenerContainer handleListenerSetupFailure Setup of JMS message listener invoker failed for destination 'queue://myqueue' - trying to recover. Cause: Connection closed
DefaultMessag I org.springframework.jms.listener.DefaultMessageListenerContainer refreshConnectionUntilSuccessful Successfully refreshed JMS Connection
but stops taking messages off the queue.
Digging a bit into Spring code, I found that setting on DefaultMessageListenerContainer
<property name="cacheLevel" value="0"/>
solves the problem, in the sense that the messages are now being read off the queue every time I send them. However, looking at the TCP traffic to WebSphere MQ I find that MQCLOSE/MQOPEN commands are sent to it repeatedly as in:
Wireshark captured traffic
which probably means that the connection gets continuously closed and reopened.
Can anybody suggest what might be the cause for caching not working properly, and whether there is perhaps a relatively simple way to modify Spring code (extending DefaultMessageListenerContainer, for example), or perhaps set some property on MQ queue connection factory/queue, to get it working?
EDIT:
Searching further the internet, I have found the following link
http://forum.spring.io/forum/spring-projects/integration/jms/89532-defaultmessagelistenercontainer-cachingconnectionfactory-tomcat-and-websphere-mq
which seems to describe a similar problem occurring on Tomcat. The solution there is to set a certain exceptionListener on DefaultMessageListenerContainer. However, trying to do this on WebSphere throws the exception "javax.jms.IllegalStateException: Method setExceptionListener not permitted". The underlying cause seems to be that J2EE 1.4 spec forbids calling setExceptionListener on JMS connections.
https://www.ibm.com/developerworks/library/j-getmess/j-getmess-pdf.pdf
It seems that setting
<property name="cacheLevel" value="0"/>
on DefaultMessageListenerContainer is actually the correct solution.
I mislead myself by interpreting MQCLOSE/MQOPEN I saw on Wireshark captured TCP traffic in this case, as the heavyweight connection opening.
First, the newly created Connection Factory on the administrative console WebSphere AS 6.1 has by default a JMS connection pool (max size 10). By debugging the base class of DefaultMessageListenerContainer, AbstractPollingMessageListenerContainer, (specifically the method
protected boolean doReceiveAndExecute(
Object invoker, Session session, MessageConsumer consumer, TransactionStatus status)
)
one sees that neither the call to create a connection, neither the call to create a session from connection generate TCP traffic, and TCP traffic is generated only by creating a consumer (considered to be a "lightweight operation" if I understand correctly), trying to receive a message from the queue, and closing the consumer.
So it seems that the connection is taken from the respective pool, and also the session is somehow "cached".
So instead of caching by Spring, the caching appears to be done here by the application server.

Grails - RabbitMQ and listener - too more onMessage call

At first I have application where I'm using RabbitMQ and Grails.
I defined listeners:
<bean id="rabbitListenerCreateDocument" class="org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="queues" ref="rabbitQueuePageInstanceCreated" />
<property name="defaultRequeueRejected" value="false"/>
<property name="messageListener" ref="createPageService" />
<property name="errorHandler" ref="errorHandlerService" />
<property name="transactionManager" ref="mongoTransactionManager"/>
<property name="autoStartup" value="true" />
<property name="concurrentConsumers" value="0" />
</bean>
The problem is that onMessage method from createPageService run too more times.
I think because I got this error (when I turn onlogs from spring):
connection error; reason: com.rabbitmq.client.impl.UnknownChannelException: Unknown channel number 10
After some time I got that spring dosnt send ack to rabbit when this exception was thrown.
Everything should look fine, but...
In'm method onMessage I'm creating document in MongoDB - and I'm geting too much documents - it CRITICAL in my app.
I'm using Mongo to store some objects, and as we all know MongoDB is not transactional.
I think that scenario looks like this:
Listener getting message
method onMessage from createPageService is running
method creating document in Mongo
method onMessage reach to end
Spring want to send ACK to rabbit but it get UnknownChannelException
TransactionManager want to rollback but it can't - there is no transaction on MongoDB
The same message came one more time and now everything works ok (there is no Exception)
I trying to make some modification to solve this but it doesn’t works:
1. First I'm trying to add Around aspect on onMessage method - it dosnt works ... I'm getting:
Error creating bean with name 'grailsApplicationPostProcessor': BeanPostProcessor before instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.config.internalTransactionAdvisor': Cannot resolve reference to bean 'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0' while setting bean property 'transactionAttributeSource'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0': BeanPostProcessor before instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.aop.aspectj.AspectJPointcutAdvisor#0': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.springframework.aop.aspectj.AspectJPointcutAdvisor]: Constructor threw exception; nested exception is java.lang.IllegalArgumentException: error at ::0 formal unbound in pointcut
I define new transaction manager for connection for bean: createPageService. It not work's too..
Somebody have any idea to solve this problem ?
I've been using this plugin for grails without issues:
https://github.com/pablomolnar/rabbit-ha
It has some extra configuration, but for basics it should be enough.

Spring Batch using Sybase IQ data source

How do we properly configure Sybase datasource in a Spring Batch?
Currently I am using a JdbcPagingItemReader for reading DB and creating the data source using Tomcat DBCP. However the following error occurs on the batch run.
Caused by: java.lang.IllegalArgumentException: DatabaseType not found for product name: [Sybase IQ]
at org.springframework.batch.support.DatabaseType.fromProductName(DatabaseType.java:77)
at org.springframework.batch.support.DatabaseType.fromMetaData(DatabaseType.java:108)
at org.springframework.batch.core.repository.support.JobRepositoryFactoryBean.afterPropertiesSet(JobRepositoryFactoryBean.java:162)
at org.springframework.batch.core.configuration.annotation.DefaultBatchConfigurer.createJobRepository(DefaultBatchConfigurer.java:82)
at org.springframework.batch.core.configuration.annotation.DefaultBatchConfigurer.initialize(DefaultBatchConfigurer.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:344)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:295)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:130)
... 13 more
For reference, I am currently JConn4-7.0 jar for connectivity. There are no issues connecting to a Oracle Database though [with pool properties changed for Oracle].
Any insight would be helpful.
Please feel free to edit the question for clarity/readability.
The error you're getting is probably from not explicitly configuring the database type on your JobRepositoryFactoryBean. Without it set, we attempt to determine what type it is from the JDBC metadata. To explicitly specify Sybase as your job repository's database type, configure it via the databaseType attribute on the JobRepositoryFactoryBean like below:
<bean id="jobRepository"
class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="transactionManager" ref="transactionManager" />
<property name="databaseType" value="SYBASE" />
</bean>
You can read more about this feature in the Spring Batch documentation here: http://docs.spring.io/spring-batch/reference/html/configureJob.html#nonStandardDatabaseTypesInRepository

Remote EJB3 access from Spring

I have 2 applications - one EAR containing EJB3.0 and other its Spring client. Both deployed on same Websphere app server 7 instance i.e. same JVM.
Here are couple of client parts:
applicationContext.xml:
<bean id="ruleService" class="org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean">
<property name="jndiName" value="com.ecrd.ruleservice.Customer_Management_Service_JavaBusiness"/>
<property name="businessInterface" value="com.ecrd.ruleservice.Customer_Management_Service_JavaBusiness"/>
<property name="jndiEnvironment">
<props>
<prop key="java.naming.factory.initial">com.ibm.websphere.naming.WsnInitialContextFactory</prop>
<prop key="java.naming.provider.url">corbaloc:iiop:localhost:2809</prop>
</props>
</property>
</bean>
Client code snippet:
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Customer_Management_Service_JavaBusiness ruleService
= (Customer_Management_Service_JavaBusiness)ctx.getBean("ruleService");
This works fine. EJB access deployed in other application in same container, works.
But it does not work if I move that client to other machine in same network and just change provider URL and give remote server IP instead of localhost. JNDI lookup problem occurs
Exact Error:
Error 500: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ruleService' defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is javax.naming.NameNotFoundException: Context: CFSDDVM2399Node01Cell/nodes/CFSDDVM2399Node01/servers/server1, name: com.ecrd.ruleservice.Customer_Management_Service_JavaBusiness: First component in name com.ecrd.ruleservice.Customer_Management_Service_JavaBusiness not found. [Root exception is org.omg.CosNaming.NamingContextPackage.NotFound: IDL:omg.org/CosNaming/NamingContext/NotFound:1.0]
I can't figure out what changes (and where) are required to connect to EJB hosted in different server JVM. Any help or suggestion are welcome.
Answering myself. Error is resolved.
I work on virtual machine. All developer images were copied from a particular VM and that
brought over WAS configs (hostname, cell, node etc) with it. Remote access
worked after fixing all occurances of hostnames in serverindex.xml of the server
hosting EJB.

Spring Error: org.springframework.beans.factory.BeanCreationException

I have a web application which I am exporting as EAR and trying to deploy on Websphere 6.1 application server.
The deployment goes fine. Even, the index page loads fine which is a login screen.
However, on entering credentials and hitting enter, the next page does not load and HTTP 500 Internal Server Error is thrown.
The next page which gets loaded is a JSP having a country drop down, whose values gets fetched from database via hibernate.
I have Datasource created in Websphere with all details and even test connection succeeds.
However, I get the below error on checking the server System.out logs:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ds':
Invocation of init method failed; nested exception is javax.naming.NameNotFoundException:
Context: uschwasvmdev04Cell01/clusters/URMDUS, name: jdbc/mydbXA: First component in name
mydbXA not found. [Root exception is org.omg.CosNaming.NamingContextPackage.NotFound:
IDL:omg.org/CosNaming/NamingContext/NotFound:1.0]
The description of NameNotFoundException says:
"This exception is thrown when a component of the name cannot be resolved because it is not bound. "
JNDI Lookup in my services.xml also seems fine:
<jee:jndi-lookup id="ds" jndi-name="jdbc/mydbXA" resource-ref="true" />
What am I missing here ?
Thanks for reading!
You are using resource-ref="true". Have you created the according resource-reference in your web.xml and did you map the DataSource to the application?
If you set it to false you can do a global lookup. Otherwise you have to configure it.
It's funny, but I've done the opposite: I created the resource-reference but I forget to tell Spring to use it.
Just in case, in the namespace it's done as you can see above: resource-ref="true"
If you're configuring your beans manually:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/database" />
<property name="resourceRef" value="true" /><!-- It's false by default -->
</bean>

Resources