With App Engine, you can build web applications that use Google's scalable infrastructure and services. App Engine runs your web application using a Java 8 JVM. App Engine invokes your app's servlet classes to handle requests and prepare responses in this environment.
The App Engine platform provides many built-in API services that your code can call. Your application can also configure scheduled tasks that run at specified intervals.
Specifying the Java 8 runtime for your app
To make your app use the Java 8 runtime, add the following line
to your appengine-web.xml
file:
<runtime>java8</runtime>
The appengine-api.jar
file included with the Google Cloud CLI under
platform/google_appengine/google/appengine/tools/java/lib/impl/appengine-api.jar
represents the App Engine API for Java. You can also access this file using the
Maven
repository which lists all the versions.
You select the version of the API your application uses by including this JAR in the
application's WEB-INF/lib/
directory, or use Maven to handle dependencies. If a new
version of the Java runtime environment is released that introduces changes that
are not compatible with existing apps, that environment will have a new
major version number.
Using Maven to handle dependencies
You can use Maven to manage all of the dependencies. For example, thispom.xml
entry includes the latest App Engine API
(Rappengine-api-1.0-sdk
) available from Maven Central:
<dependency> <groupId>com.google.appengine</groupId> <artifactId>appengine-api-1.0-sdk</artifactId> <version></version> </dependency>
The sandbox
The App Engine Java runtime distributes requests for applications across multiple web servers and prevents one application from interfering with another. An App Engine app must not respond slowly. A web request to an application must be handled within the request timeout limit. Processes that exceed this limit to respond are terminated to avoid overloading the web server.Note that the only place where users can write files is the/tmp
directory.
Files in /tmp
will consume the memory allocated to your instance. The files
stored in this location are only available to this instance and only for the
lifetime of this specific instance.
The usual way for your application to get resource files is to package the files
you rely on with your application under WEB-INF
, then load them from your app
using Class.getResource()
, ServletContext.getResource()
, or similar methods.
By default, all files in the WAR are "resource files". You can exclude files from
this set using the appengine-web.xml
file.
Class loader JAR ordering
Sometimes, it might be necessary to redefine the order in which JAR files are
scanned for classes in order to resolve collisions between class names. In
these cases, loading priority can be granted to specific JAR files by adding a
<class-loader-config>
element containing <priority-specifier>
elements in
the appengine-web.xml
file. For example:
<class-loader-config>
<priority-specifier filename="mailapi.jar"/>
</class-loader-config>
This places "mailapi.jar
" as the first JAR file to be searched for classes,
barring those in the directory war/WEB-INF/classes/
.
If multiple JAR files are prioritized, their original loading order (with
respect to each other) will be used. In other words, the order of the
<priority-specifier>
elements themselves does not matter.
Threads
With the Java 8 runtime, you can create threads using App Engine's
ThreadManager API
and Java's built-in APIs, for example new Thread()
.
Currently, if you want to call App Engine APIs (com.google.appengine.api.*
),
you must call those APIs from a request thread or from a thread created using
the ThreadManager API.
An application can
- Implement
java.lang.Runnable
. - Create a thread factory by calling
com.google.appengine.api.ThreadManager.currentRequestThreadFactory()
. - Call the factory's
newRequestThread
method, passing in theRunnable
,newRequestThread(runnable)
, or use the factory object returned bycom.google.appengine.api.ThreadManager.currentRequestThreadFactory()
with anExecutorService
(e.g., callExecutors.newCachedThreadPool(factory)
).
If you create a ThreadPoolExecutor
with currentRequestThreadFactory()
then
shutdown()
must be explicitly called before the servlet request completes. Failing to do so
will cause the request to not complete and the app server to eventually fail.
Note that some libraries may create ThreadPoolExecutors for you.
An application can perform operations against the current thread, such as
thread.interrupt()
.
Each request is limited to 50 concurrent App Engine API request threads.
When using threads, use high level concurrency
objects,
such as Executor
and Runnable
. Those take care of many of the subtle but
important details of concurrency like
Interrupts
and scheduling and
bookkeeping.
Tools
Supported IDEs
Cloud Tools for IntelliJ enables you to run and debug App Engine applications inside IntelliJ IDEA. You can deploy your App Engine projects live to production without leaving the IDE.
Supported build tools
To speed up your development process, you can use the App Engine plugins for Apache Maven or Gradle:
Local development server
The development server runs your application on your local computer for development and testing. The server simulates the Datastore services. The development server can also generate configuration for Datastore indexes based on the queries the app performs during testing.
Concurrency and latency
Your application's latency has the biggest impact on the number of instances needed to serve your traffic. If you process requests quickly, a single instance can handle a lot of requests.
Single-threaded instances can handle one concurrent request. Therefore, there is a direct relationship between the latency and number of requests that can be handled on the instance per second. For example, 10ms latency equals 100 request/second/instance.Multi-threaded instances can handle many concurrent requests. Therefore, there is a direct relationship between the CPU consumed and the number of requests/second.
Java apps support concurrent requests, so a single instance can handle new requests while waiting for other requests to complete. Concurrency significantly reduces the number of instances your app requires, but you need to design your app for multithreading.
For example, if a B4 instance (approx 2.4GHz) consumes 10 Mcycles/request, you can process 240 requests/second/instance. If it consumes 100 Mcycles/request, you can process 24 requests/second/instance. These numbers are the ideal case but are fairly realistic in terms of what you can accomplish on an instance.
App Engine Java releases
All released artifacts that start with version 2.x.x
use the
open source
release mechanism. Released artifacts that start with version 1.9.9xx
or earlier use the
internal build system. See the
GitHub repository
for more details.
Environment variables
The following environment variables are set by the runtime:
Environment variable | Description |
---|---|
GAE_APPLICATION
|
The ID of your App Engine application. This ID is prefixed with 'region code~' such as 'e~' for applications deployed in Europe. |
GAE_DEPLOYMENT_ID |
The ID of the current deployment. |
GAE_ENV |
The App Engine environment. Set to standard . |
GAE_INSTANCE |
The ID of the instance on which your service is currently running. |
GAE_RUNTIME |
The runtime specified in your app.yaml file. |
GAE_SERVICE |
The service name specified in your app.yaml file. If no service name is specified, it is set to default . |
GAE_VERSION |
The current version label of your service. |
GOOGLE_CLOUD_PROJECT |
The Google Cloud project ID associated with your application. |
PORT |
The port that receives HTTP requests. |
You can define additional environment variables in your app.yaml
file,
but the above values cannot be overridden.