Skip to main content

Deep Dive into Cloud Functions

In Cloud Functions, the runtime behavior of Node.js differs somewhat from that in a local Node.js environment.

Startup Time

There are two types of startup for cloud functions:

  • Cold Start: Requires the platform to allocate computing resources, load the code, and start the Node.js process, which takes longer;
  • Warm Start: Function instances and execution processes are reused (i.e., 'instance reuse' as mentioned below), which takes very little time.

If cloud functions are not invoked within a certain period (tens of minutes), the platform will reclaim the allocated computing resources and only reallocate them when the function is invoked again; in this case, a cold start occurs.

If consecutive requests are made to cloud functions, instances that have completed cold start are reused and can begin computation in a very short time; this is a warm start.

Note

CloudBase automatically schedules and adjusts the number of instances based on the long-term access patterns of your cloud functions, ensuring optimal performance while saving your resources.

Instance Reuse

Consider the following cloud function:

let i = 0;
exports.main = async (event = {}) => {
i++;
console.log(i);
return i;
};

During the first invocation of the cloud function, the function returns a value of 1, which is as expected.

But if this cloud function is called consecutively, its return value might increment from 2 or might become 1. This is the result of instance reuse:

  • During a Warm Start, the Node.js process executing the function is reused, and the process context is preserved, so the variable i increments.
  • During a Cold Start, the Node.js process is brand new, and the code is executed in full from the beginning, returning 1 at this point.

Therefore, developers should ensure that cloud functions are stateless and idempotent when writing them, meaning the execution of a cloud function does not depend on residual information left in the runtime environment from previous executions.

Time Zone

The default time zone in cloud functions is UTC+0. Retrieving the local time in a function will result in an 8-hour difference from Beijing time.

Defining the environment variable TZ can change the time zone of the function runtime. For example, setting TZ to Asia/Shanghai specifies the function's time zone as Beijing Time.

For more information on time zones, refer to: Time Zone Database.

Note

When processing time on the server side (including cloud databases and cloud functions), you should avoid using local time that is affected by time zones and instead use absolute values such as Unix timestamps. This can prevent numerous issues caused by time zone differences between the server and client.

Asynchronous Behavior in Node.js 8

Consider the following code:

exports.main = async (event = {}, context) => {
setTimeout(() => {
console.log("rid: ", context.request_id);
}, 0);
return "ok";
};

When invoked locally, the function returns "ok", followed by the printing of the requestId.

But if you run this code in a Node.js 8 cloud function, the function still returns "ok", but the content printed by the asynchronous function in setTimeout will not appear in the logs of this invocation, for example:

screenshot0

If you invoke it a second time, you may see the print from the previous setTimeout in the invocation logs:

screenshot1

This is confusing to many developers.

For asynchronous functions, after the main process (e.g., await main(event, context) in the example) completes execution, the function instance process will be frozen. All asynchronous tasks within the process will be suspended until the process is resumed.

On the other hand, if the function instance process is not reused due to certain reasons (e.g., the function code is updated), the code in this asynchronous process will never be executed.

Note

Developers should not place critical code in the asynchronous flow of Node.js 8 cloud functions. To ensure critical code runs stably, place it in the main function flow or use cloud functions with Node.js 10 or later:

Example

The asynchronous nature of Node.js 8 cloud functions may lead to unexpected behavior, for example:

The Mini Program wx-server-sdk provides the getWXContext method to obtain contextual information (appId, openId, unionId) for the function, facilitating development. Essentially, this method reads several parameters from environment variables.

If this method is used in an asynchronous flow to obtain openId or unionId, it may cause an abnormal situation of identity drift.

Consider the following code:

const cloud = require("wx-server-sdk");

exports.main = async (event) => {
console.log("openid a: ", cloud.getWXContext().OPENID);
setTimeout(() => {
const { OPENID } = cloud.getWXContext();
console.log("openid b: ", OPENID);
}, 0);
};

If two different users access the function via the Mini Program, user A's openid is 1111, and user B's openid is 2222.

Their logs for the two invocations will be as follows:

screenshot2

screenshot3

It can be seen that the first invocation printed user A's openid, which is as expected, but the logic in the asynchronous flow was not executed during that invocation.

During the second invocation, the function instance process was reused, the asynchronous logic generated by the first invocation continued to run, printing user B's openid, while this execution actually belonged to the asynchronous flow of user A's function invocation.