how can i do for an MDB to deploy last on my wildfly - ejb-3.0

What is happening to me is that the MDB receives messages and tries to process them and even my server has not started completely
any idea how to solve this?

You can find out if your server startup is completed by one of the following two techniques:
use ServletContextListener, once your application deployment is complete, server would call ServletContextListener.contextInitialized method
Use mbean support from wildfly, you can query mBean via JMX interface of wildfly and figure out if the server state is 'started'. But mind you, your code would be tied down to wildfly only in this case.
Once you decide the option to figure out the server startup state, you need to check for it in your MDB's postconstruct method and go ahead only if the server is started.
#MessageDriven(...)
public class MyMdb implements MessageListener {
#PostConstruct
public void init() {
// check if server has started here
//if server is not started, sleep and re-check again.
}
public void onMessage(Message message) {
}
}

Related

Endpoint startup notification in Liberty

Using Microprofile Liberty server, I need to notify another service on startup that will callback my service on https endpoint. By the way the https endpoint is not always started and inbound service may receive some connection errors.
Options I could imagine are: retry on other service or verify https availability doing rest calls before notifying other service.
Is there any built in way to be notified that endpoint is started or available using MBean notification or CDI event ?
I'm not totally clear on the use case, but it seems like you need to perform an operation (attempting to call another service) on startup? If that's the case, you could try using a CDI bean that listens to the startup event like this:
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Initialized;
import javax.enterprise.event.Observes;
#ApplicationScoped
public class StartupNotification {
public void notifyOtherService(#Observes #Initialized(ApplicationScoped.class) Object context) {
// this will be invoked on application startup
// run code here to notify the other service on startup
}
}

Readiness probe during Spring context startup

We are deploying our spring boot applications in OpenShift.
Currently we are trying to run a potentially long running task (database migration) before the webcontext is fully set up.
It is especially important that the app does not accept REST requests or process messages before the migration is fully run.
See the following minimal example:
// DemoApplication.java
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
// MigrationConfig.java
#Configuration
#Slf4j
public class MigrationConfig {
#PostConstruct
public void run() throws InterruptedException {
log.info("Migration...");
// long running task
Thread.sleep(10000);
log.info("...Migration");
}
}
// Controller.java
#RestController
public class Controller {
#GetMapping("/test")
public String test() {
return "test";
}
}
// MessageHandler.java
#EnableBinding(Sink.class)
public class MessageHandler {
#StreamListener(Sink.INPUT)
public void handle(String message) {
System.out.println("Received: " + message);
}
}
This works fine so far: the auto configuration class is processed before the app responds to requests.
What we are worried about, however, is OpenShifts readiness probe: currently we use an actuator health endpoint to check if the application is up and running.
If the migration takes a long time, OpenShift might stop the container, potentially leaving us with inconsistent state in the database.
Does anybody have an idea how we could communicate that the application is starting, but prevent REST controller or message handlers from running?
Edit
There are multiple ways of blocking incoming REST requests, #martin-frey suggested a servletfilter.
The larger problem for us is stream listener. We use Spring Cloud Stream to listen to a RabbitMQ queue.
I added an exemplary handler in the example above.
Do you have any suggestions on how to "pause" that?
What about a servletfilter that knows about the state of the migration? That way you should be able to handle any inbound request and return a responsecode to your liking. Also there would be no need to prevent any requesthandlers until the system is fully up.
I think it can run your app pod without influence if you set up good enough initialDelaySeconds for initialization of your application.[0][1]
readinessProbe:
httpGet:
path: /_status/healthz
port: 8080
initialDelaySeconds: 10120
timeoutSeconds: 3
periodSeconds: 30
failureThreshold: 100
successThreshold: 1
Additionally, I recommend to set up the liveness probes with same condition (but more time than the readiness probes' value), then you can implement automated recovery of your pods if the application is failed until initialDelaySeconds.
[0] [ https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#define-readiness-probes ]
[1] [ https://docs.openshift.com/container-platform/latest/dev_guide/application_health.html ]
How about adding an init container which only role is the db migration stuffs without the application.
Then another container to serve the application. But be careful when deploying the application with more than 1 replica. The replicas will also execute the initcontainer at the same time if you are using Deployment.
If you need multiple replicas, you might want to consider StatefulSets instead.
Such database migrations are best handled by switching to a Recreate deployment strategy and doing the migration as a mid lifecyle hook. At that point there are no instances of your application running so it can be safely done. If you can't have downtime, then you need to have the application be able to be switched to some offline or read/only mode against a copy of your database while doing the migration.
Don't keep context busy doing a long task in PostConstruct. Instead start migration as fully asynchronous task and allow Spring to build the rest of the context meanwhile. At the end of the task just set some shared Future with success or failure. Wrap controller in a proxy (can be facilitated with AOP, for example) where every method except the health check tries to get value from the same future within a timeout. If it succeeds, migration is done, all calls are available. If not, reject the call. Your proxy would serve as a gate allowing to use only part of API that is critical to be available while migration is going on. The rest of it may simply respond with 503 indicating the service is not ready yet. Potentially those 503 responses can also be improved by measuring and averaging the time migration typically takes and returning this value with RETRY-AFTER header.
And with the MessageHandler you can do essentially same thing. You wait for result of the future in the handle method (provided message handlers are allowed to hang indefinitely). Once the result is set, it will proceed with message handling from that moment on.

How to refresh the URI end points in route builder using Apache Camel periodically?

I have a requirement where by the application will need to be periodically refreshed to subscribe from different end points. I am using Apache Camel for orchestration and I am comfortable subscribing to an end point.
I have a routebuilder class as follows:
public class SampleRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
String... subscriptionTopicUris = someService.getUris();
// Simple logic - read from URIs and write to topic
from(subscriptionTopicUris) //
.to(destinationUri) //
.routeId("SAMPLE_ROUTE_ID");
}
}
I run a scheduled job with a given time interval and I remove the route from Camel Context, stop the context and add it back and start the context. However, the configure method is not fired on starting the context and hence the service (someService) possibly returning a different list of URIs is never fired.
How do I reload the route?
I am using Spring, Apache Camel and annotation based approach and this is a web application running in jetty.
Thanks

release db connections in standalone application

I am working on a standalone application using Spring/JPA and I am trying to release properly the database resources used.
In a Web application using tomcat for example, we shutdown the server, and this way, we let Tomcat manage the resources.
But as I am in a standalone app, I have to take care about this, I use Runtime.getRuntime().addShutdownHook to "catch" the shutdown event and call ((ClassPathXmlApplicationContext) context).close();, something like this:
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
((ClassPathXmlApplicationContext) context).close();
}
It works but with an exception in the stacktrace if a thread was using a connection.
I am wondering if there is another option? Maybe getting a list of open transactions and force them to rollback?
I believe that you would need to implement something like this and inside your destroy method, you would retrieve your datasource and call a close method or something similar. I'm also assuming you have a few things to do when you shutdown your application.
I can't quite help with the right method name as I don't know what you are using for your datasource.

JBoss JDBC MBean Prevent Startup If Server Not Found

During JBoss startup I have a Persistence Manager that depends on a JDBC connection (DefaultDS). The JDBC connection starts fine whether or not it can actually connect to the database so when the Persistence Manager starts it thinks it has a connection. Then it blows up because it cannot connect to the database and never starts. This prevents my DestinationManager from starting and causes all kinds of headache.
Is there a way to make MBeans that depend on the JDBC connection not start unless the JDBC connection can actually connect to the database? As an alternative, is there a way to make the JDBC connection depend on an MBean that is only active while the database can be connected to?
tl;dr; All I need is for my MBeans/DestinationManager to wait until the database (DefaultDS) is available before booting.
Please comment if you need more info about the enviornment.
JBoss version 4.2.3
Database: MsSql
If I understand the issue correctly, you're having a problem because even though the DefaultDS data source reports that it has started, since it has not acquired any connections, you don't necessarily know that connections can be made .
Unfortunately, even with the prefill option enabled, the datasource service will still start normally even if it cannot make a connection.
Your best bet is to implement a ServiceMBean that checks an actual connection from the datasource before it reports being started. For this example, we'll call it org.bob.ConnChecker and will deployed using the ObjectName org.bob:service=ConnChecker.
Your deployment descriptor should look something like this:
<mbean code="org.bob.ConnChecker" name="jboss.mq:service=DestinationManager">
<depends optional-attribute-name="DataSource">jboss.jca:name=DefaultDS,service=ManagedConnectionPool</depends>
</mbean>
So your service will not be started until the data source has started. Your service will not start unless it can get a connection. Now you just have to add org.bob:service=ConnChecker as a dependency of the DestinationManager:
jboss.mq:service=MessageCache
jboss.mq:service=PersistenceManager
jboss.mq:service=StateManager
jboss.mq:service=ThreadPool
jboss:service=Naming
org.bob:service=ConnChecker
The code for ConnChecker will look something like this:
....
import org.jboss.system.ServiceMBeanSupport;
....
public class ConnChecker extends ServiceMBeanSupport implements ConnCheckerMBean {
/** The ObjectName of the data source */
protected ObjectName dataSourceObjectName = null;
/** The Datasource reference */
protected DataSource dataSource = null;
/**
* Called by JBoss when the dataSource has started
* #throws Exception This will happen if the dataSource cannot provide a connection
* #see org.jboss.system.ServiceMBeanSupport#startService()
*/
public void startService() throws Exception {
Connection conn = null;
try {
// Get the JNDI name from the DataSource Pool MBean
String jndiName = (String)server.getAttribute(dataSourceObjectName, "PoolJndiName");
// Get a ref to the DataSource from JNDI
lookupDataSource(jndiName);
// Try getting a connection
conn = dataSource.getConnection();
// If we get here, we successfully got a connection and this service will report being Started
} finally {
if(conn!=null) try { conn.close(); } catch (Exception e) {}
}
}
/**
* Configures the service's DataSource ObjectName
* #param dataSourceObjectName The ObjectName of the connection pool
*/
public void setDataSource(ObjectName dataSourceObjectName) {
this.dataSourceObjectName = dataSourceObjectName;
}
/**
* Acquires a reference to the data source from JNDI
* #param jndiName The JNDI binding name of the data source
* #throws NamingException
*/
protected void lookupDataSource(String jndiName) throws NamingException {
dataSource = (DataSource)new InitialContext().lookup(jndiName);
}
}
The code for ConnCheckerMBean looks like this:
....
import org.jboss.system.ServiceMBeanSupport;
....
public interface ConnCheckerMBean extends ServiceMBean {
public void setDataSource(ObjectName dataSourceObjectName);
}
So you will still get errors if connections cannot be made to the database, but the DestinationManager will not start, and hopefully that will be better than the headaches you're having now.
So there is no way to have a bunch of beans just "waiting" and still
allow Jboss to boot all the way up?
Not in any standard fashion. The JBoss boot cycle either runs through to completion or reports a dependency failure. The process is sequential and single-threaded (until JBoss 7).
What you could do (and I only briefly tested this) is:
Re-implement the ConnChecker to run its connection test in a separate thread. It will be considered started as soon as that thread is spawned.
Pull out all the XML config files for services you want to depend on ConnChecker (I guess this would be all JMS deployment XML) files into another directory outside of deploy, say for example /jboss/server/bob/late-deploy.
Since the late-service files are now not in the URLDeploymentScanner's list of paths, they will not be deployed as part of the default deployment process.
The trick to getting the late-service files to deploy is that your new ConnChecker will happily spin, waiting to get a connection (and might possibly timeout and stop right there) but when it does successfully acquire a connection, it will execute code that looks like this:
import javax.management.*;
.....
// The JBoss URL Deployment Scanner MBean ObjectName
ObjectName on = new ObjectName("jboss.deployment:flavor=URL,type=DeploymentScanner");
// server is the JBossMBean server. ServiceMBeans automatically have this reference.
server.invoke(on, "addURL", new Object[]{new URL("file:/jboss/server/bob/late-deploy")}, new String[]{String.class.getName});
So what this does is tell the deployment scanner "start looking in this directory too" and a couple of seconds later, your late-services will deploy, hopefully error free. Additionally, since you added the late-service at runtime (and therefore non-persistently), when the server restarts, the deployment scanner will be reverted back to it's original configuration, waiting for ConnChecker to add new URLs to it.
Just make sure that the deployer has ScanEnabled set to true and that the ScanPeriod is low enough that you get the required response time to deploy your late-services once the JDBC connection is made. That MBean configuration is in
<jboss-home>/server/<server-name>/conf/jboss-service.xml
Look for this:
<mbean code="org.jboss.deployment.scanner.URLDeploymentScanner"
name="jboss.deployment:type=DeploymentScanner,flavor=URL">
....
<!-- Frequency in milliseconds to rescan the URLs for changes -->
<attribute name="ScanPeriod">5000</attribute>
<!-- A flag to disable the scans -->
<attribute name="ScanEnabled">true</attribute>
....
</mbean>

Resources