We have a large Java 8 Spring Hibernate Maven project that is getting larger.
Problems :
Build time is 10-12 minutes at best; 3 minutes without tests
We already have a command-line switch to skip rarely modified modules, which is the symptom of the build process reaching practical limits
Eclipse is struggling to manage the project (although IntelliJ is ok for now)
Things are getting worse as the project grows, and as more scenarios from the test team get incorported as integration tests in the code base.
How we work now
The project is configured in about 20 Maven modules, like so:
Parent
|--- Tier1
|--- Tier2
|--- WebTier
|---- ModuleA
|---- ModuleB
|---- ModuleC
|---- ...
|---- Entities
|---- Shared
|---- Batch
|---- IntegrationTests
The application is built as a single WAR
Developers deploy a single tier (typically WebTier) as an artefact from Eclipse or IntelliJ to their local Tomcat
Although the project seems nicely split in modules, there are many undesired coupling points between them. Specially in Shared, where modules needing "cross-modules" access put their services
All integration tests are in a dedicated module (no idea why)
Ideas to make it better
Add a MessageBroker module to allow loose coupling where relevant. Maybe JMS, or simply a dumb in-memory component for synchronous communication
Get rid of the Shared module
Make sure modules have coarse-grained entry-points
Remove undesired coupling between siblings and prefer the message broker when possible
Might keep Entities. At least the core-business entities (Customer, CustomerFile, ...). But some entities obviously belong to a single module (a batch execution info would be in the Batch module)
That way, anyone making a change to ModuleA would most of the time only build and run tests in that module without fearing to break the application.
Questions
Does that seem like a good plan? By good, I mean future-proof, with good chances to improve things, and not requiring an excessive amount of work given the situation
Should we have 1 Eclipse/IJ project per tier, let the IDE build the artefact and deploy it to Tomcat, or should we have 1 project per module, and dependencies toward Nexus? Or maybe the latter option is overkill?
Any other suggestions?
Some metrics
Windows 7, Java 8, Maven 3.0.3, TestNG.
SSD or 7200rpm HDD (limited impact)
6Gb RAM
Heap 1Gb (maven)
CI with Jenkins
Thanks a bunch!
CI would be real answer but it looks that your project is not modular as it should be. You don't build entire project from scratch every time. You build jars, test them in different projects and then use as single items. Each project should be small enough and cover just one area. Do you think that Java builds let's say security jars when they work on io package? Divide and conquer - that's the whole idea of OOP and encapsulation.
This might not be as bad as you think. Involved projects with unit tests and static analysis take a while.
A company I worked for had >1hr build + unitTest + CodeCoverage integration times. That doesn't count the time needed to ship the artifact off to vSphere for automated clickthrough testing of the installer on 26 languages x 8 supported OSes.
Related
We have a multi-module Maven project that takes about 2 hours to build and we would like to speed that up by making use of concurrency.
We are aware of the -T option which (as explained i.e. here) allows using multiple threads within the same JVM for the build.
Sadly, there is a lot of legacy code (which uses a lot of global states) in the project which makes executing multiple test in parallel in a single JVM very hard. Removing all of these blockers from the project would be a lot of work which we would like to avoid.
The surefire and failsafe plugins have multiple options regarding parallel execution behavior, however, as I understand it, this would only parallelize the test executions. Also, spawning a separate JVM for each test (class) seems kind of overkill to me. That would probably just as soon cause the build to take even longer than it does now.
Ideally, we would like to do the parallelization on the Maven reactor level and have it build each module in its own (single threaded) JVM with up to x JVMs running in parallel.
So my question is: is there a way to make maven create a separate JVM for each module build?
Alternatively, can we parallelize the build while making sure that tests (over all modules) are executed sequentially?
I am not completely sure this works but I guess if you use Maven Toolchains, then each module will start its own forked JVM for the tests, not reusing already running ones.
I guess it is worth a try.
I have several java projects with small differences between them for each client, those differences are:
differences in jrxml reports
differences in properties files
Changes in static classes
When I go to update the clients, I committed to SVN and generating the WAR for each project (approx 90mb) using Jenkins, upload to FTP and install it on each server.
The problem I'm having is the time it takes me to do it this way, which is between 3 and 4 hours for 6 projects every week.
It is possible that all clients are handled by a single project (single WAR) and separate the differences outside the war?
What would be the best way to do this?
This is recommended or is there a better way to handle this?
It is possible that all clients are handled by a single project (single WAR) and separate the differences outside the war?
Sure but... bear with me for a second.
With 4 hours of building/deployment time i'd say the bandwith between the jenkins server and you production servers could be the issue. If upgrading it is not viable you will need to optimize your projects setup.
Usually 90% of the size of a war file is composed by the collection of libraries your application relies on to do his job (spring, hibernate, struts and so on...).
Supposing you currently store them in your WEB-INF/lib folder, you could consider to extract those and install them in your application server shared classpath, removing them from your war.
It will not shock me if after this operation you will not need further optimizations...
I found that when I need to save time, this command saves me every time:
rsync -razpv --delete /folder/name server_name:/folder/name
you can also add:
--exclude 'file/inside/folder'
Use it cleanly, and wisely, but a process of copying files for some of my builds that took 20 minutes always, now take 10 seconds when there is no change, and less than 1 minute when there is a change.
Also - did you think about a management tool (puppet/chef/ansible) to do some of the work?
I have a test war file that contains many tests. Each test is packaged in maven project with a lot of dependencies. We use maven for dependency management but it comes with a problem. When a test update a common library, it can break other test that depends on the older version of the lib. How to make all the test run in a completely separate environment with its own set of library version? I can't execute them in a separate jvm because these tests need to be executed very frequently like very 30 sec or so. Can OSGi help solve this problem?
Yes OSGi can solve this problem, but it is not a step to be taken lightly. Use OSGi when you are ready to commit time and effort to isolating and managing dependencies, versioning them properly and, optionally, making your code and architecture more modular/reusable.
Bear in mind that adopting OSGi can be painful at first due to non-modular practices used by some legacy libraries.
All -
we have several web applications, all based on some version of Spring developed over time by different team across organizations. They each produce their own WAR, have a different context to work within, and often gets deployed on the same machine, as their functionalities are closely knit together. So we end up with:
tomcat/webapps/{A, B, C ... }
upon deployment, each use a very similar set of tool chains, replicate all Spring jars and dependencies all around.
I am wondering if there is a way to make the project structure better, deploy as a SINGLE war, while allowing each webapp live in their own source repo and have its own pace of development??
Any pointer or references are much appreciated.
Oliver
Deploying in a single WAR will couple all the projects together. Modifying one will mean redeploying all, with the accompanying QA effort to validate and do regression. I wouldn't recommend that.
Multiple copies of Spring JARs can be addressed by putting them in the Tomcat /lib; they're loaded by the Tomcat class loader instead of the WAR class loader. That will mean that every app has to be on the same version of Spring; upgrading one means upgrading all. You'll have to regression test all at once.
What harm is separate WAR files doing you? What do you care if the Tomcat /webapps directory has lots of deployments? One advantage is that they CAN be on separate release schedules. That's a big one to give away. Be sure you have a good reason before doing it.
you would have to probably move to an app server like jboss, but couldn't you use an ear file and have maven build the modules for you? That way you could probably put them in separate repos if you want each with it's own pom and then have another project with a pom for the ear file:
here is the maven ear plugin:
http://maven.apache.org/plugins/maven-ear-plugin/
here is an older blog post about multiple spring app ear file (single applicationContext fo all wars to share if you need):
http://blog.springsource.com/2007/06/11/using-a-shared-parent-application-context-in-a-multi-war-spring-application/
Based on one of your comments to another response, it sounds like you might be more interested in maven's multi-module project feature. This will allow you to define a parent POM with consistent dependencies and project layouts managed across multiple projects.
You might benefit from combining each project into a single WAR, but I do think this is really one of those 'the grass is always greener' problems. One key thing I would keep in mind is figuring out how much longer (or shorter!) is redeployment going to take if the projects were combined.
Think about OSGi. You can deploy all the dependencies just once, build your separate but interrelated modules as OSGi bundles, and deploy and upgrade them all independently. You can also choose whether to deploy them all as WARs (web bundles) or to deploy them as JARs with one or many WARs importing them to tie everything up. Virgo Web Server, formerly Spring DM Server, is really nice and comes ready to do this kind of stuff right out of the box.
I know PAX is doing a lot of stuff and that creating the container and copying all those jars is not cheap but are there any general tips to improve performance. I have tests that execute outside the container in a fraction of a second while inside they take much longer. I am using PAX primarily to verify that my manifests are accurate and the bundle would be deployable without any missing dependencies. I have tried Knopflerfish, Equinox, Felix and in general there is little difference they are relatively slow to a barebones containerless run.
As you realised, the underlying container does not make much of a difference.
If you want to have minimal bundles created on the fly, you can try out Pax Tinybundles: if this applies to your case, you can build a set of minimized bundles with only the content you actually need for testing. For example, you can just package your Manifest. I haven't benchmarked it myself for this particular purpose, but it is worth a shot.
As a sidenote, please consider that Pax Exam 2.3 introduced support (see here) for #Before and #After, thus coming to your rescue for more flexible load setup/teardown.
Using Native Container is faster than Pax Runner Container, saving the overhead of starting an external process.
Using EagerSingleStagedReactorFactory saves the overhead of restarting the framework for each test.
To avoid copying JARs, prefer mvn: URLs or mavenBundle() to general URLs, then bundles will be taken from your local Maven repository, once they have been downloaded.
A new feature in Pax Exam 2.3.0 is the reference: protocol which allows you to provision bundles in place, without copying - this works even for exploded bundles (i.e. an unzipped directory structure).