Calling Cloud Functions from other functions

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.

What is serverless?

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.

Cloud server
Cloud server

How to trigger the event

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.

Calling Cloud Functions

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 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
}

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 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
}

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
}
Code demonstrates publishing and receiving messages using Google Cloud Pub/Sub

Explanation

  • 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.

Copyright ©2024 Educative, Inc. All rights reserved