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.
Runtimes
Cloud Functions supports multiple language runtimes. You'll need the Runtime ID value if you're deploying functions from the command line or through Terraform.
Runtime | Base image | Runtime ID |
---|---|---|
Node.js 6 (decommissioned) | Debian 8 | nodejs6 |
Node.js 8 (deprecated) | Ubuntu 18.04 | nodejs8 |
Node.js 10 | Ubuntu 18.04 | nodejs10 |
Node.js 12 | Ubuntu 18.04 | nodejs12 |
Node.js 14 | Ubuntu 18.04 | nodejs14 |
Python 3.7 | Ubuntu 18.04 | python37 |
Python 3.8 | Ubuntu 18.04 | python38 |
Go 1.11 (deprecated) | Ubuntu 18.04 | go111 |
Go 1.13 | Ubuntu 18.04 | go113 |
Java 11 | Ubuntu 18.04 | java11 |
.NET Core 3.1 | Ubuntu 18.04 | dotnet3 |
Ruby 2.6 | Ubuntu 18.04 | ruby26 |
Ruby 2.7 | Ubuntu 18.04 | ruby27 |
Updates to the runtimes are generally done automatically, unless otherwise notified. All runtimes receive automatic updates to the language version as they are made available to the language community. Similarly, Cloud Functions might apply updates to other aspects of the execution environment, such as the operating system or included packages. These updates help keep your function secure.
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 might be handled by different function instances, which don’t share global variables, memory, file systems, or other state:
Node.js
Python
Go
Java
C#
Ruby
If you need to share state across function invocations, your function should use a service such as Datastore, Firestore or Cloud Storage to persist data. For a complete list of available storage options, see Choosing a storage option.
Auto-scaling and Concurrency
Cloud Functions handles incoming requests by assigning them to instances of your function. Depending on the volume of requests, as well as the number of existing function instances, Cloud Functions may assign a request to an existing instance or create a new one.
Each instance of a function handles only one concurrent request at a time. This means that while your code is processing one request, there is no possibility of a second request being routed to the same instance. Thus the original request can use the full amount of resources (CPU and memory) that you requested.
In cases where inbound request volume exceeds the number of existing instances, Cloud Functions may start multiple new instances to handle requests. This automatic scaling behavior allows Cloud Functions to handle many requests in parallel, each using a different instance of your function.
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.
Controlling auto-scaling behavior
Cloud Functions allows you to set a limit on the total number of function instances that can co-exist at any given time. In some cases, unbounded scaling is undesirable. For example, your function might depend on a resource (such as a database) that cannot scale up to the same degree as Cloud Functions. A huge spike in request volume might result in Cloud Functions creating more function instances than your database can tolerate.
Cold starts
A new function instance is started in two cases:
When you deploy your function.
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 and your code. Requests that include function instance startup (cold starts) can 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 can 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 versus 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.
Node.js
Python
Go
Java
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 period is not guaranteed to execute, and it can be stopped at any time. Therefore, you should always signal the end of your function execution correctly and avoid running any code beyond it. See HTTP Functions and Background Functions for guidance.
For example, the code executed after sending the HTTP response could be interrupted at any time:
Node.js
It's important to take into account the execution timeline when initializing your application. Background tasks should not be created in the global scope during initialization, as they execute outside of the duration of a request.
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 the asynchronous nature of handling events, in which there is no caller that waits for the response. The system might, in rare circumstances, invoke a background function more than once in order to ensure delivery of the event. If a background function invocation fails with an error, it will not be invoked again unless retries on failure are enabled for that function.
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:
HTTP functions should return appropriate HTTP status codes which denote an error. See HTTP Functions for examples.
Background functions should log and return an error message. 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 might be restarted before handling the next invocation. This can 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 duration, which you can specify at function deployment time. By default, a function times out after 1 minute, but you can extend this period up to 9 minutes.
When function execution exceeds the timeout, an error status is immediately returned to the caller. CPU resources used by the timed-out function instance are throttled and request processing may be immediately paused. Paused work may or may not proceed on subsequent requests, which can cause unexpected side effects.
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 might never execute:
Node.js
Python
Go
Java
In some circumstances, the above code may execute successfully but in an
unexpected manner. Consider the scenario when the function times out. The
instance that is serving the request is paused (by throttling the CPU). Pending
work is paused. If a subsequent request is routed to the same instance, work
resumes and Function running...
is emitted to Logs.
A common symptom of this behavior is the appearance that work and logs from one request are "leaking" into a subsequent request. Because you cannot depend on paused work being resumed, you should not rely on this behavior. Instead, your function should avoid timeouts using a combination of the following techniques:
- Set a timeout that is higher than your expected function execution time.
- Track the amount of time left during execution and perform cleanup/exit early.
To set a function's maximum execution time using the gcloud
command-line tool,
use the --timeout
flag at deploy time:
gcloud functions deploy FUNCTION_NAME --timeout=TIMEOUT FLAGS...
In the above command, FLAGS...
refers to other
options that you pass during deployment of your function. For a complete
reference for the deploy
command, see
gcloud functions deploy
.
You can also set the timeout during function creation in the Cloud Console, as follows:
Go to the Cloud Functions Overview page in the Cloud Console.
Click Create function.
Fill in the required fields for your function.
View the advanced settings by clicking More.
Enter a value in the Timeout field.
Memory
To set a function's memory using the gcloud
command-line tool, use the
--memory
flag with the
number of megabytes (128
, 256
, 512
, 1024
, 2048
, 4096
). For example:
gcloud functions deploy FUNCTION_NAME --memory=MEMORY
By default, the memory allocated to each function is 256MB.
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 can be different than the current working directory.
The following example lists files located in the function directory:
Node.js
Python
Go
Java
C#
Ruby
You can also load code from other files deployed with the function.
The only writeable part of the filesystem is the /tmp
directory, 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 as shown below:
Node.js
Python
Go
Java
C#
Ruby
Try to reuse network connections across function invocations, as described in Optimizing Networking. However, note that a connection that remains unused for 2 minutes might 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 Datastore, 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 a Pub/Sub topic to trigger a Pub/Sub function.