From golang-boost
Provides guidance on using the boost Pub/Sub adapter for Go event-driven services on GCP, including the canonical path and a production workaround for context loss on shutdown.
How this skill is triggered — by the user, by Claude, or both
Slash command
/golang-boost:boost-bootstrap-adapter-pubsubThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
**REQUIRED BACKGROUND:**
REQUIRED BACKGROUND:
boost-bootstrap-function — handler typing rule.boost-factory-pubsub — *pubsub.Client construction.boost-bootstrap-middleware — recovery/logger/publisher chain.boost-extra-middleware — NewAnyErrorWrapper for the workaround path.import (
apubsub "github.com/xgodev/boost/bootstrap/function/adapter/contrib/cloud.google.com/pubsub/v1"
"github.com/xgodev/boost/bootstrap/function"
)
fn, _ := function.New[*cloudevents.Event](rec, lmi, pmi)
fn.Run(ctx, handle, apubsub.New[*cloudevents.Event](pb))
Fine for prototypes. Not safe for production graceful shutdown — see next section.
bootstrap/function/adapter/contrib/cloud.google.com/pubsub/v1/helper.go:51 hard-codes:
if err := subscriber.Subscribe(context.Background()); err != nil { ... }
A signal.NotifyContext passed to fn.Run(ctx, ...) reaches the middleware wrapper but not the subscription receive loop. SIGTERM does not gracefully drain in-flight messages.
The same shape exists in the NATS and Kafka adapter helpers.
Bypass fn.Run and drive NewSubscriber directly with a signal-aware ctx:
import (
apubsub "github.com/xgodev/boost/bootstrap/function/adapter/contrib/cloud.google.com/pubsub/v1"
"github.com/xgodev/boost/extra/middleware"
"github.com/xgodev/boost/bootstrap/function"
)
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
opts, err := apubsub.DefaultOptions()
if err != nil { log.Fatalf("subscriber options: %v", err) }
// TODO(boost-upstream): bootstrap/function/adapter/contrib/cloud.google.com/pubsub/v1/helper.go:51
// hard-codes context.Background(), so fn.Run cannot drain SIGTERM. Bypassing
// helper here and driving NewSubscriber with a signal-aware ctx + the same
// recovery → logger → publisher chain. Collapse back to fn.Run once the
// helper accepts a ctx parameter (track upstream issue).
wrp := middleware.NewAnyErrorWrapper[*cloudevents.Event](
ctx, "bootstrap", rec, lmi, pmi,
)
wrappedHandler := function.Wrapper[*cloudevents.Event](wrp, handle)
var wg sync.WaitGroup
for _, sub := range opts.Subscriptions {
wg.Add(1)
go func(name string) {
defer wg.Done()
s := apubsub.NewSubscriber[*cloudevents.Event](pb, wrappedHandler, name, opts)
if err := s.Subscribe(ctx); err != nil && !errors.Is(err, context.Canceled) {
log.WithField("subscription", name).Errorf("subscriber exited: %v", err)
}
}(sub)
}
<-ctx.Done()
wg.Wait()
The // TODO(boost-upstream): block is not optional documentation — it's the marker that says "this is a workaround for a known upstream issue, not a stylistic choice". Without it:
fn.Run.boost-upstream to inventory all such workarounds across the codebase.| Red flag | Fix |
|---|---|
pubsub.Client.Subscription(...).Receive(...) directly | Use apubsub.NewSubscriber(...).Subscribe(ctx) |
Bypass of fn.Run without // TODO(boost-upstream): naming helper.go:51 | Add the comment, OR use canonical fn.Run and accept ungraceful shutdown |
apubsub.New[T] returning T = cloudevents.Event (value) | T = *cloudevents.Event everywhere in the chain |
npx claudepluginhub xgodev/boost --plugin golang-boostConstructs a Google Cloud Pub/Sub client in a Go service using the boost factory wrapper. Covers fpubsub.NewClient, lifecycle, and sharing the client between publisher and subscriber.
Writes idiomatic Go with goroutines, channels, interfaces, generics, and robust error handling. Optimizes performance with pprof and enforces production-grade testing patterns.
Implements concurrent Go patterns, builds microservices with gRPC/REST, optimizes performance with pprof, and enforces idiomatic Go. Use for goroutines, channels, generics, gRPC, CLI tools, benchmarks, or table-driven testing.