Deploy Vaadin App to Google Cloud App Engine with Java 17
Vaadin’s ease of use makes it a popular choice for building web applications. However, deploying a Vaadin application to Google Google Cloud App Engine can present some hidden challenges. It was not as straightforward as expected, so I want to share my findings.
The example project is available on GitHub: https://github.com/simasch/vaadin-appengine-demo
The Vaadin Application
First, I’ve created a new Vaadin application: https://start.vaadin.com
Then I did a production build:
mvn package -Pproduction
That will generate an executable JAR file in the target directory.
First Deployment
This JAR file I’ve deployed to App Engine using the CLI:
gcloud app deploy
This seemed to work, but when I tried to access the app, I got an error in the logs
java.lang.UnsupportedClassVersionError: io/seventytwo/demo/gae/Application has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 55.0
Google App Engine uses Java 11 by default, but I want to use Java 17.
Using Java 17
But how can I configure another Java version? After reading the documentation, I found out that I can add an app.yaml in the src/appengine folder with this content:
runtime: java17
Maven Plugin
I also noticed that I could use a Maven plugin to deploy the application:
<plugin> <groupId>com.google.cloud.tools</groupId> <artifactId>appengine-maven-plugin</artifactId> <version>2.4.2</version> <configuration> <projectId>GCLOUD_CONFIG</projectId> <version>GCLOUD_CONFIG</version> </configuration> </plugin>
So I simply can execute:
mvn package appengine:deploy -Pproduction
After the deployment was finished, I tried to access the application again. This time it failed with this message:
java.lang.NullPointerException: Cannot invoke "java.io.RandomAccessFile.length()" because "this.cache" is null at javax.imageio.stream.FileCacheImageOutputStream.close ( javax/imageio.stream/FileCacheImageOutputStream.java:229 ) at javax.imageio.ImageIO.write ( javax/imageio/ImageIO.java:1598 ) at com.vaadin.flow.server.PwaIcon.setImage ( com/vaadin.flow.server/PwaIcon.java:220 )
Memory Limit
The exception comes from the PWA support of Vaadin, so I removed the @PWA annotation and the application run. But looking at the logs, I’ve found issues with memory limits:
Exceeded soft memory limit of 256 MB with 262 MB after servicing 1 requests total. Consider setting a larger instance class in app.yaml.
By default, an instance of type F1 is allocated, which was not enough to start the Vaadin application.
So finally, I configured an F2 instance in the app.yaml
runtime: java17 instance_class: F2
Session State
As you may know, Vaadin applications have server state and may also have push enabled that will use WebSockets. We must enable session affinity to ensure that our application runs correctly in multiple instances.
This can be done in the app.yaml as well
network: session_affinity: true
But what does session affinity mean? Let’s check the documentation:
session_ | Optional. Set to true to configure App Engine to route multiple sequential requests for a given user to the same App Engine instance such as when storing user data locally during a session. Session affinity enables inspecting the value of a cookie to identify multiple requests by the same user and then directs all such requests to the same instance. If the instance is rebooted, unhealthy, overloaded or becomes unavailable when the number of instances has been scaled down, session affinity will be broken and further requests are then routed to a different instance. Note that enabling session affinity can affect your load balancing setup. This parameter is disabled by default. |
Conclusion
While the Maven plugin simplifies deployment, analyzing log files and configuring the Java version, instance size, and session affinity are crucial steps for a successful Vaadin application deployment on Google App Engine. By following these guidelines and addressing potential configuration issues, you can ensure a smooth and efficient deployment process.
If you encounter any issues during deployment, feel free to get in touch!