Building and Deploying GCP Cloud Pub/Sub trigger Function with Reusable Golang Code
Google Cloud Functions offer a serverless platform to build and deploy event-driven applications. Leveraging GoLang for this purpose can be efficient due to its concurrency support and performance. In this guide, we’ll walk through the process of building and deploying GCP Cloud Functions using reusable GoLang code.
Setup Environment
Ensure you have the Google Cloud SDK installed and authenticated. Install the Go programming language and set up your development environment. Also, make sure you have Go Modules enabled for dependency management.
Directory Structure
PUBSUB_CLOUD_FUNC
└── app
├── dto
│ └── item.go
├── repository
│ └── item_repo.go
├── service
│ └── item_service.go
└── cloud_func
└── new_item
├── go.mod
├── go.sum
├── key.json
└── new_item.go
└── pkg
└── util.go
└── go.mod
Implement reusable code
First, let’s create a new Go module for our project
mkdir pubsub_cloud_func
cd pubsub_cloud_func
go mod init github.com/chazool/go_medium_samples/pubsub_cloud_func/pubsubcloudfunc
repository
Package
Define your data access logic in this package.
package repository
import (
"cmp"
"slices"
"github.com/chazool/go_medium_samples/pubsub_cloud_func/pubsubcloudfunc/app/dto"
)
var items = make([]dto.Item, 0, 100)
type ItemRepo interface {
New(i dto.Item)
Get(id uint) *dto.Item
}
type ItemRepoImpl struct {
}
func NewItemRepo() ItemRepo {
return ItemRepoImpl{}
}
func (repo ItemRepoImpl) Get(id uint) *dto.Item {
i, _ := slices.BinarySearchFunc(items, dto.Item{ID: id}, func(e, t dto.Item) int {
return cmp.Compare(e.ID, t.ID)
})
return &items[i]
}
func (repo ItemRepoImpl) New(i dto.Item) {
items = append(items, i)
}
service
Package
Define your business logic in this package.
package service
import (
"errors"
"github.com/chazool/go_medium_samples/pubsub_cloud_func/pubsubcloudfunc/app/dto"
"github.com/chazool/go_medium_samples/pubsub_cloud_func/pubsubcloudfunc/app/repository"
)
type ItemService interface {
New(item dto.Item) error
}
type ItemServiceImpl struct {
ItemRepo repository.ItemRepo
}
func NewItemService() ItemService {
return ItemServiceImpl{
ItemRepo: repository.NewItemRepo(),
}
}
func (srv ItemServiceImpl) New(i dto.Item) error {
item := srv.ItemRepo.Get(i.ID)
if item != nil {
return errors.New("item already exists")
}
srv.ItemRepo.New(i)
return nil
}
utils
Package
Define your utility functions in this package.
package pkg
import (
"encoding/json"
"log"
)
func StructBuilder[T any](data []byte) (T, error) {
var v T
err := json.Unmarshal(data, &v)
if err != nil {
log.Println("Failed to unmarshal JSON", err)
return v, err
}
return v, nil
}
Write Cloud Function
Now create the cloud_func
folder and initialize a Go module for it:
mkdir cloud-function
cd cloud-function
go mod init github.com/chazool/go_medium_samples/pubsub_cloud_func/cloud_func/new_item
go.mod
File
module github.com/chazool/go_medium_samples/pubsub_cloud_func/cloud_func/new_item
go 1.22.2
replace github.com/chazool/go_medium_samples/pubsub_cloud_func/pubsubcloudfunc => ../../
require (
github.com/GoogleCloudPlatform/functions-framework-go v1.8.1
github.com/chazool/go_medium_samples/pubsub_cloud_func/pubsubcloudfunc v0.0.0-00010101000000-000000000000
github.com/cloudevents/sdk-go/v2 v2.14.0
)
require (
cloud.google.com/go/functions v1.15.3 // indirect
github.com/google/uuid v1.4.0 // indirect
github.com/json-iterator/go v1.1.10 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect
go.uber.org/atomic v1.4.0 // indirect
go.uber.org/multierr v1.1.0 // indirect
go.uber.org/zap v1.10.0 // indirect
)
Implement the Cloud Function
Create a new Go file for your Cloud Function. Let’s call it new_item.go
. This function will be triggered by Pub/Sub messages.
package new_item
import (
"context"
"fmt"
"log"
"github.com/chazool/go_medium_samples/pubsub_cloud_func/pubsubcloudfunc/app/dto"
"github.com/chazool/go_medium_samples/pubsub_cloud_func/pubsubcloudfunc/app/service"
"github.com/chazool/go_medium_samples/pubsub_cloud_func/pubsubcloudfunc/pkg"
_ "github.com/GoogleCloudPlatform/functions-framework-go/funcframework"
"github.com/GoogleCloudPlatform/functions-framework-go/functions"
"github.com/cloudevents/sdk-go/v2/event"
)
func init() {
functions.CloudEvent("newItem", NewItem)
}
type MessagePublishedData struct {
Message PubSubMessage
}
type PubSubMessage struct {
Data []byte `json:"data"`
}
func NewItem(ctx context.Context, e event.Event) error {
var msg MessagePublishedData
// Convert event data to MessagePublishedData struct
if err := e.DataAs(&msg); err != nil {
log.Printf("error converting event data: %v", err)
return fmt.Errorf("event.DataAs: %w", err)
}
// Build an Item struct from the message data
i, err := pkg.StructBuilder[dto.Item](msg.Message.Data)
if err != nil {
log.Printf("error building item structure: %v", err)
return fmt.Errorf("struct builder: %w", err)
}
// Attempt to add the new item using the service
srv := service.NewItemService()
if err := srv.New(i); err != nil {
log.Printf("error occurred while adding new item: %v", err)
return fmt.Errorf("adding item: %w", err)
}
return nil
}
Deploying the Cloud Function
If you are using any third-party dependencies, you can vendor them using go mod vendor
. This will create a vendor directory containing all the dependencies.
Create a Pub/Sub Topic
Before deploying the Cloud Function, let’s create a Pub/Sub topic.
gcloud pubsub topics create new_item
Deploy the Cloud Function
Now, it’s time to deploy your Cloud Function to Google Cloud Platform. Make sure you have the Google Cloud SDK installed and configured with your GCP project.
gcloud functions deploy new_item_test \
--gen2 \
--runtime go122 \
--trigger-topic new_item \
--source=. \
--entry-point=newItem \
--region us-central1
Conclusion
That’s it! You’ve now successfully built and deployed a Google Cloud Function triggered by Pub/Sub events using Go, with the ability to reuse common code across functions. This approach enhances scalability, maintainability, and efficiency in your event-driven architecture on Google Cloud Platform.
For further reference and to explore the code used in this tutorial, you can find the repository here.
— Happy coding! 💻😊 —