Cached library

HTTP Cloud Function that uses a cached client library instance to reduce the number of connections required per function invocation.

Documentation pages that include this code sample

To view the code sample used in context, see the following documentation:

Code sample

C++

#include <google/cloud/functions/http_request.h>
#include <google/cloud/functions/http_response.h>
#include <google/cloud/pubsub/publisher.h>
#include <nlohmann/json.hpp>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>

namespace gcf = ::google::cloud::functions;
namespace pubsub = ::google::cloud::pubsub;

namespace {
pubsub::Publisher GetPublisher(pubsub::Topic topic) {
  using Map = std::unordered_map<std::string,
                                 std::shared_ptr<pubsub::PublisherConnection>>;

  static std::mutex mu;
  static Map connections;

  std::lock_guard<std::mutex> lk(mu);
  auto [pos, inserted] = connections.emplace(
      topic.FullName(), std::shared_ptr<pubsub::PublisherConnection>());
  if (inserted) {
    pos->second = pubsub::MakePublisherConnection(std::move(topic), {});
  }
  return pubsub::Publisher(pos->second);
}
}  // namespace

gcf::HttpResponse tips_gcp_apis(gcf::HttpRequest request) {  // NOLINT
  auto const* project = std::getenv("GCP_PROJECT");
  if (project == nullptr) throw std::runtime_error("GCP_PROJECT is not set");

  auto const body = nlohmann::json::parse(request.payload());
  auto const topic_id = body.value("topic", "");
  if (topic_id.empty()) throw std::runtime_error("Missing topic in request");

  auto publisher = GetPublisher(pubsub::Topic(project, topic_id));
  auto id = publisher.Publish(
      pubsub::MessageBuilder().SetData("Test message").Build());

  gcf::HttpResponse response;
  if (!id.get()) {
    response.set_result(gcf::HttpResponse::kInternalServerError);
  } else {
    response.set_payload("1 message published");
    response.set_header("content-type", "text/plain");
  }
  return response;
}

Go


// Package contexttip is an example of how to use Pub/Sub and context.Context in
// a Cloud Function.
package contexttip

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"

	"cloud.google.com/go/pubsub"
)

// GOOGLE_CLOUD_PROJECT is a user-set environment variable.
var projectID = os.Getenv("GOOGLE_CLOUD_PROJECT")

// client is a global Pub/Sub client, initialized once per instance.
var client *pubsub.Client

func init() {
	// err is pre-declared to avoid shadowing client.
	var err error

	// client is initialized with context.Background() because it should
	// persist between function invocations.
	client, err = pubsub.NewClient(context.Background(), projectID)
	if err != nil {
		log.Fatalf("pubsub.NewClient: %v", err)
	}
}

type publishRequest struct {
	Topic   string `json:"topic"`
	Message string `json:"message"`
}

// PublishMessage publishes a message to Pub/Sub. PublishMessage only works
// with topics that already exist.
func PublishMessage(w http.ResponseWriter, r *http.Request) {
	// Parse the request body to get the topic name and message.
	p := publishRequest{}

	if err := json.NewDecoder(r.Body).Decode(&p); err != nil {
		log.Printf("json.NewDecoder: %v", err)
		http.Error(w, "Error parsing request", http.StatusBadRequest)
		return
	}

	if p.Topic == "" || p.Message == "" {
		s := "missing 'topic' or 'message' parameter"
		log.Println(s)
		http.Error(w, s, http.StatusBadRequest)
		return
	}

	m := &pubsub.Message{
		Data: []byte(p.Message),
	}
	// Publish and Get use r.Context() because they are only needed for this
	// function invocation. If this were a background function, they would use
	// the ctx passed as an argument.
	id, err := client.Topic(p.Topic).Publish(r.Context(), m).Get(r.Context())
	if err != nil {
		log.Printf("topic(%s).Publish.Get: %v", p.Topic, err)
		http.Error(w, "Error publishing message", http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, "Message published: %v", id)
}

Node.js

const {PubSub} = require('@google-cloud/pubsub');
const pubsub = new PubSub();

/**
 * HTTP Cloud Function that uses a cached client library instance to
 * reduce the number of connections required per function invocation.
 *
 * @param {Object} req Cloud Function request context.
 * @param {Object} req.body Cloud Function request context body.
 * @param {String} req.body.topic The Cloud Pub/Sub topic to publish to.
 * @param {Object} res Cloud Function response context.
 */
exports.gcpApiCall = (req, res) => {
  const topic = pubsub.topic(req.body.topic);

  topic.publish(Buffer.from('Test message'), err => {
    if (err) {
      res.status(500).send(`Error publishing the message: ${err}`);
    } else {
      res.status(200).send('1 message published');
    }
  });
};

Python

import os
from google.cloud import pubsub_v1

# Create a global Pub/Sub client to avoid unneeded network activity
pubsub = pubsub_v1.PublisherClient()


def gcp_api_call(request):
    """
    HTTP Cloud Function that uses a cached client library instance to
    reduce the number of connections required per function invocation.
    Args:
        request (flask.Request): The request object.
    Returns:
        The response text, or any set of values that can be turned into a
        Response object using `make_response`
        <http://flask.pocoo.org/docs/1.0/api/#flask.Flask.make_response>.
    """

    project = os.getenv('GCP_PROJECT')
    request_json = request.get_json()

    topic_name = request_json['topic']
    topic_path = pubsub.topic_path(project, topic_name)

    # Process the request
    data = 'Test message'.encode('utf-8')
    pubsub.publish(topic_path, data=data)

    return '1 message published'

What's next

To search and filter code samples for other Google Cloud products, see the Google Cloud sample browser