Java Runtime Environment
This article serves as a thorough introduction to Cloud Engine’s Java runtime environment. To quickly get started with Cloud Engine, see Getting Started With Cloud Engine.
You can deploy WAR and JAR projects built with Maven to Cloud Engine, or upload WAR files directly to Cloud Engine.
If you are looking to start a new project, we recommend that you use one of our sample projects as a boilerplate:
Running a Java program usually costs a large amount of memory. If you are using a trial instance with 256M of memory, Cloud Engine might encounter an OOM error when starting your Java program, causing your deployment to fail. Even if Cloud Engine is able to start your program, the program might frequently get restarted due to low memory.
We recommend that you pick an instance with at least 512 MB of memory. If your project is built with Spring Boot, a minimum of 1024 MB of memory is recommended. You can adjust the memory size at any time even if you've already deployed your project. See Cloud Engine Platform Features § Adjusting Quota and Number of Instances for more information on how to adjust the memory size of your instances.
Startup Command
Once the build is finished, Cloud Engine will look for a .war
or .jar
file under target
:
- If it finds a
.war
file, it will place the file into a Servlet container (Jetty 9.x). - If it finds a
.jar
file, it will run the file withjava -jar
.
Configure JVM Parameters
When Cloud Engine runs a Java application, it will give -Xmx
a value equivalent to 70% of the size of the instance. The remaining 30% will be reserved for off-heap memory and other consumptions. You may customize the value of -Xmx
if your application has special needs (like using a large amount of off-heap memory). For example, if your instance has a memory of 2 GB, you can add a custom environment variable on Cloud Engine’s Settings page with JAVA_OPTS
as its name and -Xmx1500m
as its value. This will limit the size of the JVM heap to 1.5 GB and leave 500 MB for PermGen, off-heap memory, and other stuff. Keep in mind that if the value of -Xmx
is too small, a large amount of CPU might be wasted on repetitive garbage collection tasks.
Configure Java Version
To specify the Java version you want to use, create a file named system.properties
under the root directory of your project:
java.runtime.version=11
At this time, Cloud Engine supports AdoptOpenJDK 8
, 11
, 12
, 13
, and 14
.
Upload WAR File
If you’ve already built the WAR file on your local computer (with commands like mvn package
), you can add the --war
option when you deploy your project with the CLI. This tells the CLI to upload the WAR file rather than the source code.
tds deploy --war
In this case, Cloud Engine won’t install dependencies or build your project on the server side. Instead, it will run the WAR file by placing it into a Servlet container.
Install Dependencies and Build
If you’ve uploaded the source code, Cloud Engine will install the dependencies listed in pom.xml
with Maven and build your project by running mvn package
.
Customize Build Process
You can override the default behavior by specifying startup commands (run
), dependency installation commands (install
), and build commands (build
) in leanengine.yaml
:
run: echo 'run another command'
install:
- {use: 'default'}
- echo 'install additional dependencies here'
build:
- echo 'overwrite default build command here'
See Reference: leanengine.yaml for more information. Below are a few examples:
Upload Jar Without Building on the Server
runtime: java
install: []
build: []
run: java -jar your-package.jar
Here we have specified that we are using the Java Runtime Environment. We have skipped the dependency installation and build steps by leaving them empty. We also specified the run command (run your-package.jar
in the root directory).
System Dependencies
You can specify the system dependencies provided by the server-side environment using leanengine.yaml
:
systemDependencies:
- imagemagick
See Reference: leanengine.yaml for a complete list of supported system dependencies.
Build Logs
By default, the logs generated during the build process won’t be printed to the console. If the build process fails, the logs from the last completed step will be printed to the console.
To print the complete build log for debugging, check Print build logs if you are deploying from the dashboard or add --options 'printBuildLogs=true'
if you are deploying with the CLI.
Health Check
Cloud Engine is primarily optimized for web applications. Your app is expected to provide HTTP services through the port specified by the environment variable named LEANCLOUD_APP_PORT
. Keep in mind that the app should listen on 0.0.0.0
(all interfaces) instead of 127.0.0.1
which is the default host of many frameworks.
While your app is being deployed, Cloud Engine will check your app every second to see if it has been successfully started. If your app has not been started within the time limit (30 seconds by default), the deployment will be canceled. After your app has been deployed, Cloud Engine will run health checks for your app regularly and automatically restart it if the check fails.
The way the health check works is that Cloud Engine will send an HTTP request to the homepage (/
) of your app. If it gets an HTTP 2xx response, your app will pass the health check.
Health check and the Cloud Engine SDK
Cloud Engine will also check /__engine/1/ping
which is handled by the SDK. If the SDK is integrated correctly, Cloud Engine will not check the homepage (/
) anymore.
If Developer Center > Your game > Game Services > Cloud Services > Cloud Engine > Manage deployment > Your group > Settings > Cloud functions mode is set to Enable, or if functionsMode
in leanengine.yaml
is set to strict
, Cloud Engine will check if the SDK is integrated correctly. If not, it will consider your app to have failed to start.
Customizing startup timeout (startupTimeout
)
The default timeout for your app to start is 30 seconds. You can change it to any value between 15 and 120 seconds with leanengine.yaml
:
startupTimeout: 60
Cloud Environment
Custom Domains
Projects deployed to Cloud Engine can only be accessed with domains configured. You can bind domains by going to Developer Center > Your game > Game Services > Cloud Services > Cloud Engine > Manage deployment > Your group > Settings > Domains.
If you bind a domain that starts with stg-
(e.g., stg-api.example.com
), it will be assigned to the staging environment automatically.
We provide shared domains for apps that are still under testing. You can assign your app a shared domain with a prefix of your choice.
Load Balancer and CDN
All HTTP and HTTPS requests sent to Cloud Engine will go through a load balancer that deals with chores including HTTPS encryption, HTTPS redirection, and response compression. You won’t have to implement features for handling these tasks yourself for the programs hosted on Cloud Engine. Meanwhile, the load balancer brings the following restrictions that your program cannot bypass:
- Paths starting with
/.well-known/acme-challenge/
are used by Cloud Engine to automatically renew certificates. Requests sent to these paths won’t be forwarded to your program. - The size of a request header (URL and headers) should be within 64K and each line of the request header should be within 8K.
- The size of a request (for uploading files) should be within 100M.
- The timeout for connecting or waiting for a response is 60 seconds.
Getting the Client IP Address
Cloud Engine’s load balancer includes the following information depicting the original request in the HTTP header:
X-Real-IP
: The original IP address.X-Forwarded-Proto
: The original protocol (http
orhttps
).Forwarded
: Information about the proxy, defined by RFC 7239. It contains the IP address and the protocol.
EngineRequestContext.getRemoteAddress();
HTTPS Redirect
When you bind a custom Cloud Engine domain, you can enable Force HTTPS to have the load balancer redirect HTTP requests to HTTPS while keeping the paths.
Environment Variables
The following environment variables are available for your application to use:
Variable name | Description |
---|---|
LEANCLOUD_APP_ID | The App ID of the current application. |
LEANCLOUD_APP_KEY | The App Key of the current application. |
LEANCLOUD_APP_MASTER_KEY | The Master Key of the current application. |
LEANCLOUD_APP_ENV | The environment your application is running in. If you are running your application on your local computer, the value will be non-existent or development (if you are starting your application with the CLI). It will be stage for the staging environment and production for the production environment. |
LEANCLOUD_APP_PORT | The port opened up for your application. Your application has to listen on this port in order for users to access your service. |
LEANCLOUD_API_SERVER | The address used to access the Data Storage service. Please use this value if your application needs to access the Data Storage service or other cloud services with the REST API. |
LEANCLOUD_APP_GROUP | The group the instance is located at. |
LEANCLOUD_REGION | The region the application is running in. It will be CN for Mainland China and US for the United States. |
LEANCLOUD_VERSION_TAG | The version number of the deployment. |
You can also set up custom environment variables on the dashboard to store configurations.
Logs
See Cloud Engine Platform Features § Viewing Logs for more information on how to view logs and access logs on the dashboard.
Cloud Engine will collect the logs your application has printed to standard output (stdout) and standard error (stderr):
Each line of the logs can contain a maximum of 4096 characters. A maximum of 600 lines of logs can be collected every minute. The logs generated by your application that exceed these limits will be discarded.
Timezone
The timezone used on the server side is UTC+0.
File System
Your application can create temporary files under /home/leanengine
and /tmp
. The size limit for all the files created by your application is 1 GB.
Each time you trigger a new deployment for your application, Cloud Engine will create a new container for it. Even though you don’t trigger deployments, Cloud Engine will still perform occasional maintenance operations. This means that your application should not treat the file system provided by Cloud Engine as permanent storage.
If the files created by your application bear relatively larger sizes, we recommend that your application always cleans them up once it finishes using them. Creating more files when there are already more than 1 GB files existing might lead to the Disk quota exceeded
error. You can trigger a deployment to quickly clean up all the temporary files.
IP Addresses
Some third-party platforms (like Weixin Open Platform) may require that you provide an IP address whitelist. You can obtain the inbound and outbound IP addresses used by Cloud Engine on Developer Center > Your game > Game Services > Cloud Services > Cloud Engine > Manage deployment > Your group > Settings > Inbound IP and outbound IP.
We will do our best to minimize the frequency of changing the inbound and outbound IP addresses, but there remains the possibility for them to get changed. If you encounter any problems with IP addresses, the first thing you can do is look at the IP addresses displayed on the dashboard and see if they have been changed.
To get a fixed inbound IP address for your application, consider enabling dedicated IP.
Troubleshooting
Can I run my Cloud Engine Java project locally without using the CLI?
Once you have configured the environment variables required for running your project on Cloud Engine, you can run your Java project locally with certain commands or using an IDE without using the CLI.
To run a Jetty or JAR project from the command line, first configure the environment variables:
eval "$(lean env)"
Notice that lean env
outputs the commands used to configure the environment variables required for the current application. You can use eval
to execute these commands.
If you’re using Windows, you need to manually configure the environment variables returned by lean env
.
If you have a Jetty project, run the following command:
mvn jetty:run
If you have a JAR project, package it with Maven and run the following command:
mvn package
java -jar target/{zipped jar file}
To run the application with Eclipse:
Please first make sure that you have installed the Maven plugin with Eclipse, then import the project into Eclipse as a Maven Project.
After this, right-click on the project under the Package Explorer view:
- For a Jetty project, select Run As > Maven build… and set Goals under the Main tab to be
jetty:run
. - For a JAR project, select Run As > Run Configurations…, select
Application
, and setMain class:
(cn.leancloud.demo.todo.Application
for the sample project).
Then add the following environment variables under the Environment tab:
Name | Value |
---|---|
LEANCLOUD_APP_ENV | development |
LEANCLOUD_APP_ID | {{appid}} |
LEANCLOUD_APP_KEY | {{appkey}} |
LEANCLOUD_APP_MASTER_KEY | {{masterkey}} |
LEANCLOUD_APP_PORT | 3000 |
Once you’ve finished the configuration above, you will be able to run your project by hitting run.
If my project depends on private libraries, can I use them on Cloud Engine?
You can follow the instructions below to use private libraries on Cloud Engine:
- Create a directory named
libs
under the root directory of your project, then copy all the jar files your project depends on into it. - Create a file named
leanengine.yaml
under the root directory of your project, then customize theinstall
stage (see the example below). - Edit the dependencies in
pom.xml
and addincludeSystemScope
intospring-boot-maven-plugin
in the same file (see the example below).
Your project structure will look like this:
{root}
|---libs
| |- yourdependency.jar etc.
|---leanengine.yaml
\---pom.xml
leanengine.yaml
will look like this:
install:
- require:
- libs
- { use: "default" }
To add dependencies into pom.xml
:
<dependency>
<groupId>com.sample</groupId>
<artifactId>sample</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/libs/yourdependency.jar</systemPath>
</dependency>
Edit spring-boot-maven-plugin
in pom.xml
so it looks like this:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>