Creating database schema in WildFly eagerly

I’m using Camunda 7.6.0 as shared engine in WildFly 10.1 (Camunda’s bundle download).

Once I deploy my application I start to access the Camunda database immediately (done by a ServletContextListener) because I setup my own tables using liquibase and also use this framework to add indexes to Camunda tables. Everything works fine as long as the Camunda database schema was initialized previously. I use Docker to setup a continous integration environment and there I experience the problem that my WAR file seems to “wakeup” the shared engine but this action does not block: The Camunda tables are created a couple of seconds after my ServletContextListener fires and liquibase setup occurs. Then I get a lot of “table not found” errors when liquibase tries to add those indexes to Camunda tables.

In the WAR I have

  • META-INF/processes.xml
  • @ProcessApplication based on ServletProcessApplication
  • jboss-deployment-structure.xml to define a dependency to the Camunda shared engine

My questions are:

  1. Is there a way to force the Camunda shared engine to create the database schema eagerly on WildFly boot and not when the first application deploys which got Camunda dependencies? I think this behavior is up to WildFly’s module loading system which starts modules on demand. So may be there is no way for this solution :frowning:
  2. Annother possibilty would be to block the ServletProcessApplication until the schema is created and I hook liquibase to the deploy()-method of that class. Of cource I tried this possiblity but it does not work in this way.

What I did so far:

  1. I did everything as documented. So I’m pretty sure that my WAR contains everything neccessary to start Camunda properly. But I might be wrong :wink:.
  2. I replaced my ServletContextListener by a CDI singleton with Startup annotation. Same behavior.
  3. I added a CDI injection of the Camunda RepositoryService into my liquibase setup class and did a query. I hoped this would force the creation of the tables. It didn’t work, neither for the ServletContextListener nor for the CDI singleton. If the tables are missing I get a NPE. If not the query works.

Whatevery I do the Camunda tables are created a couple of seconds after my deployment. Unfortunally I even cannot add a delay because the tables created by liquibase are needed by jobs running also at deploy time. To be precise I use another EAR deployment (which got a dependency to the WAR deployment) which uses the tables created by liquibase.

I hope someone can help to clarify how Camunda’s database schema creation works and how I can achieve my goal.

Thx,
Stephan

Stephan,

During startup of Widfly processing of modules (Camunda) and processing of the deployments happens in parallel mode.
With the reference to the Camunda engine module in your jboss-deployment-structure.xml the classpath of your application is enhanced by the classes provided by this module. This does not delay the access to this module until it’s completely started.
Your application does not “wakeup” Camunda engine. Camunda ist not started lazily, it will start work eagerly (JobExecutor). Even if there is no deployed process yet.

There is another Wildfly specific deployment artifact jboss-all.xml. But from what I read you can define startup dependencies between deployments only with this, not between a deployment and a module.

One thing that should work:
Camunda creates a jndi binding when startup is done:
INFO [org.camunda.bpm.container.impl.jboss.service.MscManagedProcessEngine#createProcessEngineJndiBinding] jndi binding for process engine default is java:global/camunda-bpm-platform/process-engine/default

If you reference this binding in your ServletContextListener with e.g.
@Resource( name = "java:global/camunda-bpm-platform/process-engine/default" )
this should delay the startup of it until the binding is available.

Regards, Frank

1 Like

Your Wildfly knowledge is really helpful, Frank. Thank you.

1 Like

Hi Frank,

Thank you for your hint. I’m already in weekend but I will try this next week.

I will tell you whether it works in my situation.

Thank you,
Stephan

@hawky4s had another idea: Could you trigger the liquibase migrations from an @PostDeploy-annotated method of your process application?

Also, if you have a shared engine and want to modify it, wouldn’t it more natural to do this via a separate process engine plugin instead of having this in an application (since the engine’s lifetime does not depend on the application’s lifetime)?

Unfortunally this doesn’t work. I added

@Resource(name = "java:global/camunda-bpm-platform/process-engine/default")
private ProcessEngine processEngine;

and a WEB-INF/jboss-deployment-structure.xml

<jboss-deployment-structure>
   <deployment>
      <dependencies>
         <module name="org.camunda.bpm.camunda-engine" export="TRUE" />
      </dependencies>
   </deployment>
</jboss-deployment-structure>

I get no error if I don’t use the injected object, so Camunda classes are known within the WAR. But the deployment is not delayed until Camunda is initialized completly.

By the way: If I access the ProcessEngine injected (I called “processEngine.getName()”) I get a NPE:

07:54:39,280 ERROR [org.jboss.msc.service.fail] (ServerService Thread Pool -- 73) MSC000001: Failed to start service jboss.undertow.deployment.default-server.default-host./nvbp-server-domainmodel-dbversioning: org.jboss.msc.service.StartException in service jboss.undertow.deployment.default-server.default-host./nvbp-server-domainmodel-dbversioning: java.lang.RuntimeException: java.lang.NullPointerException
	at org.wildfly.extension.undertow.deployment.UndertowDeploymentService$1.run(UndertowDeploymentService.java:85)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
	at org.jboss.threads.JBossThread.run(JBossThread.java:320)
Caused by: java.lang.RuntimeException: java.lang.NullPointerException
	at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:231)
	at org.wildfly.extension.undertow.deployment.UndertowDeploymentService.startContext(UndertowDeploymentService.java:100)
	at org.wildfly.extension.undertow.deployment.UndertowDeploymentService$1.run(UndertowDeploymentService.java:82)
	... 6 more
Caused by: java.lang.NullPointerException
	at de.nuernberger.nvbp.dbversioning.JBossLiquibaseServletListener.contextInitialized(JBossLiquibaseServletListener.java:16)
	at io.undertow.servlet.core.ApplicationListeners.contextInitialized(ApplicationListeners.java:187)
	at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:198)
	... 8 more

I tried this before - it didn’t work either.

Every application uses the ProcessEngine in a certain way. In my situation the application got a lot of CallActivities-hierarchies so the application needs an index on the ACT_HI_PROCINST.SUPER_PROCESS_INSTANCE_ID_. There are two other indexes required for this application to run with good performance.

We decided to manage the database layer by the application itself (by using Liquibase). So from this point of view it is up to each application installed into the container to initialize the database.

Another aspect I mentioned is the fact that we use docker to setup our CI environment. The environment is dropped every time a build takes place. The database is always empty and has to be initialized - by Camunda and the application.

Another thought: In the last weeks we were thinking about using Docker images as deployment artifacts. This would give us the safety that the “thing” running in production is exactly the same thing as tested before. Not only the deployment, the entire system. In this situation we also would let build our Docker images by the build server and deploy them in a target environment.

Another thought: Usually we build EAR deployments. So as mentioned in my very first post I cannot obviate that there is something wrong to my WAR. Is there a “sample” WAR in the consulting repository which I could use to check whether my WAR is erroneous?

I gave it try but you were right: This jboss-all.xml

<jboss umlns="urn:jboss:1.0">
	<jboss-deployment-dependencies xmlns="urn:jboss:deployment-dependencies:1.0">
		<dependency name="org.camunda.bpm.camunda-engine"/>
	</jboss-deployment-dependencies>
</jboss>

brings

08:31:29,453 ERROR [org.jboss.as.controller.management-operation] (Controller Boot Thread) WFLYCTL0013: Operation ("deploy") failed - address: ([("deployment" => "dbversioning.war")]) - failure description: {"WFLYCTL0180: Services with missing/unavailable dependencies" => ["jboss.deployment.unit.\"dbversioning.war\".PARSE is missing [jboss.deployment.unit.\"org.camunda.bpm.camunda-engine\".deploymentCompleteService]"]}

Concerning the NPE: It is thrown before the JNDI binding of Camunda is done.

08:36:30,302 ERROR [org.jboss.msc.service.fail] (ServerService Thread Pool -- 70) MSC000001: Failed to start service...Caused by: java.lang.NullPointerException
....
08:36:31,607 INFO  [org.camunda.bpm.container.impl.jboss.service.MscManagedProcessEngine] (ServerService Thread Pool -- 62) jndi binding for process engine default is java:global/camunda-bpm-platform/process-engine/default

The only reason for this I can imagine is (if JNDI binding works as expected) that the logging of the succeeded binding is not at the same time as the binding itself.

As injection i sobviously not working the deployment does not wait for module availability.
I did not recognize from you original post, that you were talking about a war deployment. I have no experience with this combination.
Just a wild guess: try
@Resource(mappedName = "java:global/camunda-bpm-platform/process-engine/default")
If this does not work either, create a small project to reproduce your problem. Otherwise it will we not possible to help you further.
Another thing you might want to take into account is, to post your problem on Wildfly dicussion forum at https://developer.jboss.org/en/wildfly/content/.