Triggering from Pub/Sub push

You can use Pub/Sub to push messages to the endpoint of your Cloud Run service, where the messages are subsequently delivered to containers as HTTP requests. You cannot use Pub/Sub pull subscriptions because Cloud Run only allocates CPU during the processing of a request.

You should process the message and then return a response when finished.

Leveraging service accounts and IAM permissions, you can securely and privately use Pub/Sub with Cloud Run, without having to expose your Cloud Run service publicly. Only the Pub/Sub subscription that you have set up is able to invoke your service.

Possible use cases include:

This page shows how to enable your service to securely process messages pushed from a Pub/Sub subscription in the same Google Cloud project.

To integrate your service with Pub/Sub,

  • Create a Pub/Sub topic.
  • Add code in your Cloud Run service to respond to the Pub/Sub messages sent to the topic you created.
  • Create a service account with the required permissions.
  • Create a Pub/Sub subscription and associate it with the service account. This subscription will send to your service any message that is published to the topic.

Before you start

If you haven't done so already, set up your environment as described in the setup page for Cloud Run. You'll need to use the gcloud command line and a Google Cloud project to deploy your Cloud Run service to.

Adding code to handle messages from Pub/Sub

Your service must extract the message from the request and return an expected success code. The following snippets for selected languages (you can use any language) show how to do this for a simple Hello World message:

Node.js

app.post('/', (req, res) => {
  if (!req.body) {
    const msg = 'no Pub/Sub message received';
    console.error(`error: ${msg}`);
    res.status(400).send(`Bad Request: ${msg}`);
    return;
  }
  if (!req.body.message) {
    const msg = 'invalid Pub/Sub message format';
    console.error(`error: ${msg}`);
    res.status(400).send(`Bad Request: ${msg}`);
    return;
  }

  const pubSubMessage = req.body.message;
  const name = pubSubMessage.data
    ? Buffer.from(pubSubMessage.data, 'base64').toString().trim()
    : 'World';

  console.log(`Hello ${name}!`);
  res.status(204).send();
});

Python

@app.route("/", methods=["POST"])
def index():
    envelope = request.get_json()
    if not envelope:
        msg = "no Pub/Sub message received"
        print(f"error: {msg}")
        return f"Bad Request: {msg}", 400

    if not isinstance(envelope, dict) or "message" not in envelope:
        msg = "invalid Pub/Sub message format"
        print(f"error: {msg}")
        return f"Bad Request: {msg}", 400

    pubsub_message = envelope["message"]

    name = "World"
    if isinstance(pubsub_message, dict) and "data" in pubsub_message:
        name = base64.b64decode(pubsub_message["data"]).decode("utf-8").strip()

    print(f"Hello {name}!")

    return ("", 204)

Go


// PubSubMessage is the payload of a Pub/Sub event.
// See the documentation for more details:
// https://cloud.google.com/pubsub/docs/reference/rest/v1/PubsubMessage
type PubSubMessage struct {
	Message struct {
		Data []byte `json:"data,omitempty"`
		ID   string `json:"id"`
	} `json:"message"`
	Subscription string `json:"subscription"`
}

// HelloPubSub receives and processes a Pub/Sub push message.
func HelloPubSub(w http.ResponseWriter, r *http.Request) {
	var m PubSubMessage
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Printf("ioutil.ReadAll: %v", err)
		http.Error(w, "Bad Request", http.StatusBadRequest)
		return
	}
	if err := json.Unmarshal(body, &m); err != nil {
		log.Printf("json.Unmarshal: %v", err)
		http.Error(w, "Bad Request", http.StatusBadRequest)
		return
	}

	name := string(m.Message.Data)
	if name == "" {
		name = "World"
	}
	log.Printf("Hello %s!", name)
}

Java

import java.util.Base64;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

// PubsubController consumes a Pub/Sub message.
@RestController
public class PubSubController {
  @RequestMapping(value = "/", method = RequestMethod.POST)
  public ResponseEntity receiveMessage(@RequestBody Body body) {
    // Get PubSub message from request body.
    Body.Message message = body.getMessage();
    if (message == null) {
      String msg = "Bad Request: invalid Pub/Sub message format";
      System.out.println(msg);
      return new ResponseEntity(msg, HttpStatus.BAD_REQUEST);
    }

    String data = message.getData();
    String target =
        !StringUtils.isEmpty(data) ? new String(Base64.getDecoder().decode(data)) : "World";
    String msg = "Hello " + target + "!";

    System.out.println(msg);
    return new ResponseEntity(msg, HttpStatus.OK);
  }
}

You must code the service to return an accurate HTTP response code. Success codes, such as HTTP 200 or 204, acknowledge complete processing of the Pub/Sub message. Error codes, such as HTTP 400 or 500, indicate the message will be retried, as described in Receiving messages using Push.

Create a service account for the subscription

You need to create a service account to associate with your Pub/Sub subscription, and give it the permission to invoke your Cloud Run service. Pub/Sub messages pushed to your Cloud Run service will carry the identity of this service account.

You can use an existing service account to represent the Pub/Sub subscription identity, or you can create a new one.

To create a new service account and give it permission to invoke the Cloud Run service:

Console

  1. In the Cloud Console, go to the Create service account page.

    Go to Create service account

  2. Select a project.

  3. Enter a service account name to display in the Cloud Console.

    The Cloud Console generates a service account ID based on this name. Edit the ID if necessary. You cannot change the ID later.

  4. Optional: Enter a description of the service account.

  5. Click Create.

  6. Click the Select a role field.

  7. Under All roles, select Cloud Run > Cloud Run Invoker.

  8. Click Done.

Command line

  1. Create the service account:

    gcloud iam service-accounts create SERVICE-ACCOUNT_NAME \
       --display-name "DISPLAYED-SERVICE-ACCOUNT_NAME"

    Replace

    • SERVICE-ACCOUNT_NAME with a lower case name unique within your Google Cloud project, for example my-invoker-service-account-name.
    • DISPLAYED-SERVICE-ACCOUNT-NAME with the name you want to display for this service account, for example, in the console, for example, My Invoker Service Account.
  2. For Cloud Run, give your service account permission to invoke your service:

    gcloud run services add-iam-policy-binding SERVICE \
       --member=serviceAccount:SERVICE-ACCOUNT_NAME@PROJECT-ID.iam.gserviceaccount.com \
       --role=roles/run.invoker

    Replace

    • SERVICE with the name of the service you want to be invoked by Pub/Sub.
    • SERVICE-ACCOUNT_NAME with the name of the service account.
    • PROJECT-ID with your Google Cloud project ID.

Creating a Pub/Sub topic

Requests to your service are triggered by messages published to a Pub/Sub topic, so you'll need to create a topic:

Console

  1. Visit the Pub/Sub topics page in the Cloud Console.

    Pub/Sub topics page

  2. Click Create a topic.

  3. Enter a unique Name for your topic, for example, MyTopic.

Command line

gcloud pubsub topics create TOPIC-NAME

Replace TOPIC-NAME with a topic name unique within your Google Cloud project.

Create a push subscription and associate it with the service account

After you create the Pub/Sub topic, you must subscribe your service to receive messages sent to a topic, and you must associate the subscription with the service account you created for your service. You can use either the Cloud Console or the gcloud command line:

Console

  1. Go to the Pub/Sub topics page.

    Pub/Sub topics page

  2. Click the topic you want to subscribe to.

  3. Click Create Subscription to display the subscription form:

    subscription form

    In the form,

    1. Specify the push delivery type.
    2. For Endpoints URL, specify your service's URL, which is displayed in the service detail page.
    3. In the Service Account dropdown, select the service account that you created with the required permissions.
    4. Set subscription expiration and acknowledgement deadline as desired.
    5. Click Create.
  4. The subscription is complete. Messages posted to the topic will now be pushed into your service.

Command line

  1. Allow Pub/Sub to create authentication tokens in your project:

    gcloud projects add-iam-policy-binding PROJECT-ID \
         --member=serviceAccount:service-PROJECT-NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com \
         --role=roles/iam.serviceAccountTokenCreator

    Replace

    • PROJECT-ID with your Google Cloud project ID.
    • PROJECT-NUMBER with your Google Cloud project number.

      Project ID and project number are listed in the Project info panel in the Cloud Console for your project.

  2. Create a Pub/Sub subscription with the service account that you created with the required permissions:

    gcloud beta pubsub subscriptions create SUBSCRIPTION-ID --topic TOPIC-NAME \
       --push-endpoint=SERVICE-URL/ \
       --push-auth-service-account=SERVICE-ACCOUNT-NAME@PROJECT-ID.iam.gserviceaccount.com

    Replace

    • TOPIC-NAME with the topic you previously created.
    • SERVICE-URL with the HTTPS URL that was provided when you deployed the service. You can find it by using the command gcloud run services describe, specifying the name of your service: look for the return line starting with domain.
    • PROJECT-ID with your Google Cloud project ID.

    The --push-auth-service-account flag activates the Pub/Sub push functionality for Authentication and authorization

  3. The subscription is complete. Messages posted to the topic will now be pushed into your service. You can push a test message to the topic using the command:

    gcloud pubsub topics publish TOPIC --message "hello"

    Replace TOPIC with the name of the topic you created.

What's next