Cloud Functions is a serverless computing service provided by Google Cloud. It supports programming languages such as Node.js, Python, Go, Java, and .NET. In programming, a function is a unit of code that performs a specific task and can be reused throughout the program. Just like a function in a program, when an event occurs, Cloud Functions is triggered, and the specific code is executed accordingly. There is no need to provision or manage servers with Cloud Functions.
Generally, a developer manages server provisioning in cloud computing systems, but with Google Cloud Functions, a developer only needs to write source code. Cloud automatically configures the necessary underlying infrastructure and executes and terminates the code. Cloud Functions only charges users for the time when the code is running.
Cloud Functions offer a versatile set of capabilities that can address various use cases. These functions can automate various tasks, including resizing images, converting files, and transforming data. They are also ideal for data stream processing, enabling real-time analysis of data as it flows through your system. Additionally, Cloud Functions can integrate with different APIs, allowing us to seamlessly automate workflows and exchange data between various services.
Serverless does not mean a backend without a server. Serverless refers to a backend without server management. In a traditional server-based system, the server must always be running and ready to respond to requests, even with no current workload. This can result in unnecessary costs and resource consumption. In a serverless architecture, developers upload functions are "asleep" until a request triggers their execution. When a request occurs, the Cloud Function wakes up the corresponding function and performs the requested operation. Once the operation is complete, the function returns to "sleep" until the subsequent request arrives.
The developer sets up Cloud Functions to execute in response to various scenarios by specifying a trigger for the function. A trigger can be one of many supported events:
HTTP triggers:
Incoming HTTP(S) requests.
Event triggers:
Messages coming from the Pub/Sub message cue.
Events triggered by the Firebase Mobile SDK.
The Google Cloud Storage service creates, modifies, or deletes a file.
To call a Cloud Function inside another Cloud Function, create a Pub/Sub topic and send a message to its triggering Pub/Sub topic to trigger it. Pub/Sub is a messaging service that allows services to communicate asynchronously. Pub/Sub creates event producers and consumers, called publishers and subscribers. Publishers communicate with subscribers asynchronously by broadcasting events rather than synchronous remote procedure calls (RPCs).
Let's go over how to call a Cloud Function from another Cloud Function. First, one Cloud Function publishes a message to a Pub/Sub topic, and another subscribes to the same topic and processes the incoming message.
The following example shows how to directly call a Cloud Function from another Cloud Function step-by-step. Before proceeding with the example code, it is necessary to set up Google Cloud Docker as a prerequisite.
For example, the publisher function is called publishMessage
, and the subscriber function is receiveMessages
.
Note: One Cloud Function publishes a message to a Pub/Sub topic.
In the publisher function, create a client object for the Pub/Sub service:
func publishMessage(ctx context.Context, projectID, topicID, message string) error {// Create a Pub/Sub clientclient, err := pubsub.NewClient(ctx, projectID)if err != nil {return err}// Get the topic objecttopic := client.Topic(topicID)// Create the Pub/Sub messagemsg := &pubsub.Message{Data: []byte(message),}// Publish the message to the topicif _, err := topic.Publish(ctx, msg).Get(ctx); err != nil {return err}log.Printf("Published message: %s", string(msg.Data))return nil}
Note: Another function subscribes to the same topic and processes as the incoming message.
Then, in the subscriber function, define a function that will be triggered when a new message is received. The publicMessage
function calls the receiveMessages
function after the message is published to the topic. Now, whenever a message is published to the topic, the receiveMessages
function will be called.
func receiveMessages(ctx context.Context, projectID, subscriptionID string, handlerFunc func(context.Context, pubsub.Message) error) error {// Create a Pub/Sub clientclient, err := pubsub.NewClient(ctx, projectID)if err != nil {return err}// Get the subscription objectsub := client.Subscription(subscriptionID)// Receive messages from the subscriptionerr = sub.Receive(ctx, func(ctx context.Context, msg *pubsub.Message) {if err := handlerFunc(ctx, *msg); err != nil {log.Printf("Error handling message: %v", err)msg.Nack()return}msg.Ack()})return err}
In summary, the receiveMessages
function is a Cloud Function triggered by messages published to a Cloud Pub/Sub topic in publishMessage
.
Let's have a look at the working example in the widget below:
package main import ( "context" "log" "cloud.google.com/go/pubsub" ) func main() { // Set these values to match your project and topic projectID := "golang-383504" topicID := "golang" ctx := context.Background() // Publish a message to the Pub/Sub topic if err := publishMessage(ctx, projectID, topicID, "Hello, Pub/Sub!"); err != nil { log.Fatalf("Failed to publish message: %v", err) } // Receive and process messages from the Pub/Sub subscription if err := receiveMessages(ctx, projectID, "golang-sub", HelloPubSub); err != nil { log.Fatalf("Failed to receive messages: %v", err) } } func publishMessage(ctx context.Context, projectID, topicID, message string) error { // Create a Pub/Sub client client, err := pubsub.NewClient(ctx, projectID) if err != nil { return err } // Get the topic object topic := client.Topic(topicID) // Create the Pub/Sub message msg := &pubsub.Message{ Data: []byte(message), } // Publish the message to the topic if _, err := topic.Publish(ctx, msg).Get(ctx); err != nil { return err } log.Printf("Published message: %s", string(msg.Data)) return nil } func receiveMessages(ctx context.Context, projectID, subscriptionID string, handlerFunc func(context.Context, pubsub.Message) error) error { // Create a Pub/Sub client client, err := pubsub.NewClient(ctx, projectID) if err != nil { return err } // Get the subscription object sub := client.Subscription(subscriptionID) // Receive messages from the subscription err = sub.Receive(ctx, func(ctx context.Context, msg *pubsub.Message) { if err := handlerFunc(ctx, *msg); err != nil { log.Printf("Error handling message: %v", err) msg.Nack() return } msg.Ack() }) return err } func HelloPubSub(ctx context.Context, m pubsub.Message) error { log.Printf("Received message: %s", string(m.Data)) return nil }
Line 7: We import the cloud.google.com/go/pubsub
to use the Pub/Sub API.
Line 36–46: Topic(topicID)
creates a reference to a topic in the Pub/Sub Client. Publish the msg
to the Pub/Sub topic.
Line 61–72: A subscriber client get a subscription to that topic and receives HelloPubSub
messages from the subscription.