Cloud Functions Execution Environment

Beta

This is
a beta
release of Google Cloud Functions.
This API
might be changed in backward-incompatible ways
and
is not
subject to any SLA or deprecation policy.

Cloud Functions run in a fully-managed, serverless environment where Google
handles infrastructure, operating systems, and runtime environments completely
on your behalf. Each Cloud Function runs in its own isolated secure execution
context, scales automatically, and has a lifecycle independent from other
functions.

What does this mean for your Cloud Functions design and implementation? This
document explains.

Supported Runtime & Runtime Updates

Cloud Functions offers Node.js runtime, currently in version v6.11.5. Where
possible, we will follow the "LTS" release cycle of Node and will update minor
and patch versions of the runtime as soon as or shortly after they become
available.

Base Image

Cloud Functions uses a Debian-based execution environment and includes contents
of the gcr.io/google-appengine/nodejs Docker image. To see what is included in
the image, you can check its
GitHub project, or pull
and inspect the image itself. Updates to the language runtime (Node.js) are
generally done automatically (unless otherwise notified), and include any
changes in the definition of the base image.

Concurrency

Cloud Functions may start multiple function instances to scale your function up
to meet the current load. These instances run in parallel, which results in
having more than one parallel function execution.

However, each function instance handles only one concurrent request at a time.
This means while your code is processing one request, there is no possibility of
a second request being routed to the same function instance, and the original
request can use the full amount of resources (CPU and memory) that you requested.

Because concurrent requests are processed by different function instances, they
do not share variables or local memory. This is discussed in detail later in
this document.

Stateless Functions

Cloud Functions implements the serverless paradigm, in which you just run your
code without worrying about the underlying infrastructure, such as servers or
virtual machines. To allow Google to automatically manage and scale the
functions, they must be stateless—one function invocation should not rely
on in-memory state set by a previous invocation. However, the existing state can
often be reused as a performance optimization; see the recommendation in Tips and Tricks
for details.

For example, the counter value returned by the following function does not
correspond to the total function invocation count because invocations may be
handled by different function instances, which don’t share global variables,
memory, file systems, or other state:

Cold Starts

When a new function instance is automatically created to scale up to the load,
or occasionally to replace an existing instance.

Starting a new function instance involves loading the runtime (Node.js) and
your code. Requests that include function instance startup (cold starts) may be
slower than requests hitting existing function instances. If your function
receives steady load, however, then the number of cold starts is typically
negligible unless your function frequently crashes and requires restarting of
the function environment. See Errors to
learn how to handle errors properly and avoid cold starts.

Function Instance Lifespan

The environment running a function instance is typically resilient and reused by
subsequent function invocations, unless the number of instances is being scaled
down (due to lack of ongoing traffic), or your function crashes. This means that
when one function execution ends, another function invocation may be handled by
the same function instance. Therefore, it is recommended to cache state across
invocations in
global scope
where possible. Your function should be still prepared to work without this
cache available as there is no guarantee that the next invocation will reach the
same function instance
(see Stateless Functions).

Function Scope vs. Global Scope

A single function invocation results in executing only the body of the function
declared as the entry point. The global scope in the function file, which is
expected to contain the function definition, is executed on every
cold start, but not if the instance
has already been initialized.

You can assume that the global scope has been executed exactly once before your
function code is invoked in a new function instance (and on every subsequent
creation of a new function instance). However, you should not depend on the
total number of or timing of global scope executions as they depend on the
autoscaling managed by Google.

Function Execution Timeline

A function has access to the resources requested (CPU and memory) only for the
duration of function execution. Code run outside of the execution periods is not
guaranteed to execute, and it may be stopped at any time. Therefore, you should
always signal the end of your function execution correctly
(see HTTP Functions and
Background Functions for guidance),
and avoid running any code beyond it.

For example, the code executed after sending the HTTP response could be
interrupted at any time:

Execution Guarantees

Your functions are typically invoked once for each incoming event. However,
Cloud Functions does not guarantee a single invocation in all cases because of
differences in error scenarios.

The maximum or minimum number of times your function is going to be invoked on a
single event depends on the type of your function:

HTTP functions are invoked at most once. This is because of the synchronous
nature of HTTP calls, and it means that any error on handling function
invocation will be returned without retrying. The caller of an HTTP function
is expected to handle the errors and retry if needed.

Background functions are invoked at least once. This is because of
asynchronous nature of handling events, in which there is no caller that waits
for the response and could retry on error. An emitted event invokes the
function with potential
retries on failure (if requested on
function deployment) and sporadic duplicate invocations for other reasons
(even if retries on failure were not requested).

To make sure that your function behaves correctly on retried execution attempts,
you should make it idempotent by implementing it so that an event results in
the desired results (and side effects) even if it is delivered multiple times.
In the case of HTTP functions, this also means returning the desired value even
if the caller retries calls to the HTTP function endpoint. See
Retrying Background Functions
for more information on how to make your function idempotent.

Errors

The recommended way for a function to signal an error depends on the function
type:

Background functions should return an error object through the callback
parameter (if using the callback syntax), or a rejected promise (if using the
promise syntax). See Background Functions
for examples.

If an error is returned the recommended way, then the function instance that
returned the error is labelled as behaving normally and can serve future
requests if need be.

If your code or any other code you call throws an uncaught exception or crashes
the current process, then the function instance may be restarted before handling
the next invocation. This may lead to more
cold starts, resulting in higher
latency, and thus is discouraged.

See Reporting Errors for more
discussion of how to report errors in Cloud Functions.

Timeout

Function execution time is limited by the timeout value, specified at function
deployment time. It defaults to 1 minute, and can be extended up to 9 minutes.
When function execution exceeds the timeout, an error status is immediately
returned. Any remaining code that is executing may be terminated.

For example, the snippet below includes code that is scheduled to execute 2
minutes after function execution starts. If the timeout happens to be set to 1
minute, this code may never execute:

File System

The function execution environment contains a runnable function file, plus files
and directories included in the deployed function package such as
local dependencies. These files are available in a read-only directory, which
can be determined based on the function file location. Note that the function’s
directory may be different than the current working directory.

The only writeable part of the file system is the /tmp directory (as defined
by os.tmpdir()), which you can
use to store temporary files in a function instance. This is a local disk mount
point known as a "tmpfs" volume in which data written to the volume is stored in
memory. Note that it will consume memory resources provisioned for the function.

The rest of the file system is read-only and accessible to the function.

Network

Your function can access the public internet using standard libraries offered by
the runtime or third-party providers. For example, you can call an HTTP
endpoint this way using the request module:

Try to reuse network connections across function invocations, as
described in Optimizing Networking.
However, note that a connection that remains unused for 2 minutes may
be closed by the system, and further attempts to use a closed connection will
result in a "connection reset" error. Your code should either use a library
that handles closed connections well, or handle them explicitly if using
low-level networking constructs.

Multiple Functions

Every deployed function is isolated from all other functions—even those
deployed from the same source file. In particular, they don’t share memory,
global variables, file systems, or other state.

To share data across deployed functions, you can use storage services like
Cloud Datastore,
Cloud Firestore, or
Cloud Storage. Alternatively, you can invoke one function from
another, using their appropriate triggers (for example, make an HTTP request to
the endpoint of an HTTP function or publish a message to Cloud Pub/Sub topic to
trigger a Cloud Pub/Sub function).