Optimize continuous deployment (cancel throu chain-of-responsibility)
Asked Answered
G

3

9

Id like to improove continuous delivery. I am using a Tomcat 8 and maven.

I use mvn tomcat:redeploy to deploy the webapp.

In tomcat documentation I found this part:

Deploy A New Application Archive (WAR) Remotely

If installation and startup is successful, you will receive(...)

Otherwise, the response will start with FAIL and include an error message.

As possible causes of FAIL one point is of interrest:

An exception was encountered trying to start the new web application.

So Id like to throw an exception at startup so in the web.xml I write:

<​load-on-startup>1<​/load-on-startup>

to the org.springframework.web.servlet.DispatcherServlet-Servlet. Then I write a Singleton:

@Service
public class AvoidStartupOnMissingDatabase implements SmartInitializingSingleton {

    @Override
    public void afterSingletonsInstantiated() {
        throw new RuntimeException("Do not deploy this app!");
    }
}

This causes this Stacktrace:

java.lang.RuntimeException: Do not deploy this app!
        at xxx.AvoidStartupOnMissingDatabase.afterSingletonsInstantiated(AvoidStartupOnMissingDatabase.java:11)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:775)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:762)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
        at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:664)
        at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:630)
        at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:678)
        at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:549)
        at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:490)
        at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
        at javax.servlet.GenericServlet.init(GenericServlet.java:158)
        at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1144)
        at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1091)
        at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:983)
        at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4962)
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5274)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
        at org.apache.catalina.core.StandardContext.reload(StandardContext.java:3823)
        at org.apache.catalina.startup.HostConfig.reload(HostConfig.java:1410)
        at org.apache.catalina.startup.HostConfig.checkResources(HostConfig.java:1320)
        at org.apache.catalina.startup.HostConfig.check(HostConfig.java:1648)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300)
        at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
        at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
        at org.apache.catalina.manager.ManagerServlet.check(ManagerServlet.java:1525)
        at org.apache.catalina.manager.ManagerServlet.deploy(ManagerServlet.java:773)
        at org.apache.catalina.manager.ManagerServlet.doPut(ManagerServlet.java:443)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:664)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.catalina.filters.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:108)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:613)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
        at org.apache.coyote.ajp.AjpProcessor.service(AjpProcessor.java:486)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:745)

Problem

The application unfortunately deployed!

Screenshot of ci

Question

I fail the init. I said load-on-start. Tomcat said fail if not start. Tomcat said (re)deploy if can start.

So the exception must fail the deployment. Right?

EDIT

I tested tomcat-8.5.30 as well as tomcat-8.5.37, both unfortunately succeed.

Grimes answered 3/2, 2019 at 11:47 Comment(6)
Is this your main objective? : Detect faults during the deployment and / or the start of your application?Colewort
@JR Id like to rollback deployment on err.Grimes
Do you have some continuous integration server or could you provision one?Colewort
@Colewort Yes, I use RM. On commit (Subversion) I unit-test integration-test and redeploy (deliver) the app. If the redeploy (deliver) fail the commit (Subversion) is canceled and the changes are not added to the svn.Grimes
I have not heard about RM. Maven offer several plugins to deploy but personally, I don't like to mix build configurations with security credentials in my pom.xml. Last questions in order answer your question: Deploy with maven is mandatory? Do you have a an artifact repository like Nexus or are you able to provisioning a new one?Colewort
I use RM as artifact repository. Mandatory is only rollback broken deployment. RM is also my PKI-Server, OCSP, Maven site hoster, wiki, bugtracker.Grimes
G
4

Iv created a bug in Tomcat. The developer guided me to the solution similar to Alexandru Cojocaru.

I moved from a Servlet to a SerlvetContextListener and I successfully receive a "FAIL" for the deployment.

After this invalid deployment the old application is unfortunately not restarted. But the commit to svn is canceled Successfully and is not added to the svn-change-log!

Grimes answered 10/2, 2019 at 7:53 Comment(0)
C
0

Tomcat has two options to deploy war files:

  • copy war to webapps
  • http tomcat endpoint /manager/text/deploy

More details and configurations in this answer

Also, tomcat:redeploy is not for rollback purposes, is just for deploy an existing war without necessity or package again.

I'm sure that the mvn tomcat:deploy plugin uses the /manager/text/deploy tomcat endpoint to deploy war files.

Assuming that you are using some continuous integration server (jenkins, travis, etc) or just a simple shell script to invoke the previous steps, I advice you these approaches to perform a rollback:

Rollback parameter

Add a new input parameter in your flow, called : rollback_tag or previous_version.

Rollback with Maven

Maven is the best option for compile and generate war or jar files. But for deployment purposes, I think it is not the best option. I would not like share credentials or configurations in my pom.xml (with or without variables):

<plugin>
   <groupId>org.codehaus.mojo</groupId>
   <artifactId>tomcat-maven-plugin</artifactId>
   <version>1.1</version>
   <configuration>
      <url>http://localhost:8080/manager/text</url>
      <server>TomcatServer</server>
      <path>/javaCodeGeeks</path>
   </configuration>
</plugin>

Anyway if you want to use maven, you need:

  • Search the source code of the maven plugin
  • Extend it or add new functionalities like:
    • Catch errors from tomcat deployment
    • Download the source code using some tag version
    • Redeploy in case of error

Rollback downloading again

Steps could be:

  • (1) Download the source using svn
  • (2) Execute mvn clean package
  • (3) Execute mvn tomcat:deploy
    • This command must return an exit code
    • (3.1) In case of exit_code == 0 , would indicate that your deploy was successful.
    • (3.2) In case of exit_code != 0 , would indicate an error in deployment. Continue with (4) step
  • (4) Download the source using svn but in this case you must use the rollback tag parameter and repeat the steps (2) and (3)

With some artifact repository

With this tool, We need to download source code using svn , just one time. After compile and success deploy, you must upload the war or jar file with specific version like 1.0.0 Next steps in your flow just need to download the war/jar file.

In case of error in 1.0.1 deployment, you just need to download the previous stable version 1.0.0 from your artifact repository. Steps could be:

  • (1) Detect the svn commit action of the developer and compile, test and upload the war file to the artifact repository using your continuous integration server or your shell script.
  • (2) Download the war file from the artifact repository
  • (3)Execute a curl command to upload and deploy war file. More details and configurations here:
  • (4) In case of error, download the war file from the artifact repository but in this case you must use the previous_version parameter and repeat the step (3)
Colewort answered 6/2, 2019 at 17:7 Comment(4)
Why do you think you must store credentials in the pom.xml? That you did not tell about the double-hash deployment let me think you focus the bounty but not the solution.Grimes
According to the comments : "@JR Id like to rollback deployment on err.", you are trying to rollback on error using maven. I only share some approaches to perform a rollback.Colewort
@JR SQL can not rollback commited updates. A compleated deployment is a commited deployment. A compleated deployment can not be rolled back but you can deploy an old one.Grimes
Do you need to deploy a previous war version in case a new version of the war fails to deploy? I tried to help you base on your comments.Colewort
D
0

The deployment was successful. The stack trace that you see was caused by an application runtime error, when Spring tried to load the AvoidStartupOnMissingDatabase bean. At this point, the application is already deployed and running.

If you want to make the Maven redeploy goal fail, you need to cause an error during deployment, not while the application is running. You can do this by using a wrong URL in the Maven Tomcat plugin configuration, for example.

Dronski answered 7/2, 2019 at 10:5 Comment(1)
If you read the question you will notice the org.apache.catalina.manager.ManagerServlet.deploy in the stacktrace. This is an error during deployment my friend.Grimes

© 2022 - 2024 — McMap. All rights reserved.