What does a production ready Google Cloud Function look like? [on hold]

  • A+
Category:Languages

I'm just getting started with this whole Serverless thing using Google Cloud Functions and all the examples are basically "Helloworld".

package function  import (     "net/http" )  func F(w http.ResponseWriter, r *http.Request) {     w.Write([]byte("Hello, World!/n")) } 

What does a production ready function look like?

 


Given the provider takes care of things like scaling for you the first thing I would do is focus on observability. You don't know what you don't know. I like to add my own tracing and structured logging; logging to stdout falls short in many ways.

package function  import (     "context"     "fmt"     "net/http"     "os"     "sync"      "cloud.google.com/go/logging"     "contrib.go.opencensus.io/exporter/stackdriver"     "contrib.go.opencensus.io/exporter/stackdriver/propagation"     "go.opencensus.io/trace"     "google.golang.org/genproto/googleapis/api/monitoredres" )  var (     logger *logging.Logger     once   sync.Once )  // configFunc sets the global configuration; it's overridden in tests. var configFunc = defaultConfigFunc  func F(w http.ResponseWriter, r *http.Request) {     once.Do(func() {         if err := configFunc(); err != nil {            panic(err)         }     })      defer logger.Flush()      ctx := r.Context()     var span *trace.Span      httpFormat := &propagation.HTTPFormat{}     sc, ok := httpFormat.SpanContextFromRequest(r)     if ok {         ctx, span = trace.StartSpanWithRemoteParent(ctx, "helloworld", sc,             trace.WithSampler(trace.AlwaysSample()),             trace.WithSpanKind(trace.SpanKindServer),         )         defer span.End()     }      logger.Log(logging.Entry{         Payload:  "Handling new HTTP request",         Severity: logging.Info,     })      w.Write([]byte("Hello, World!/n")) }  func defaultConfigFunc() error {     var err error      projectId := os.Getenv("GCP_PROJECT")     if projectId == "" {             return fmt.Errorf("GCP_PROJECT environment variable unset or missing")     }      functionName := os.Getenv("FUNCTION_NAME")     if functionName == "" {             return fmt.Errorf("FUNCTION_NAME environment variable unset or missing")     }      region := os.Getenv("FUNCTION_REGION")     if region == "" {         return fmt.Errorf("FUNCTION_REGION environment variable unset or missing")     }      stackdriverExporter, err := stackdriver.NewExporter(stackdriver.Options{ProjectID: projectId})     if err != nil {         return err     }      trace.RegisterExporter(stackdriverExporter)     trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})      client, err := logging.NewClient(context.Background(), projectId)     if err != nil {         return err     }      monitoredResource := monitoredres.MonitoredResource{         Type: "cloud_function",         Labels: map[string]string{             "function_name": functionName,             "region":        region,         },     }      commonResource := logging.CommonResource(&monitoredResource)     logger = client.Logger(functionName, commonResource)      return nil } 

Also, make sure you vendor all your dependencies, you really want your build to be reproducible. I'm using Go 1.11 these days, and the following works for me:

$ mkdir helloworld $ cd helloworld $ vim function.go $ echo "module github.com/kelseyhightower/helloworld" > go.mod $ go mod vendor   

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: