or run

tessl search
Log in

Version

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
golangpkg:golang/cloud.google.com/go/spanner@v1.87.0

docs

client.mddml.mdindex.mdkeys.mdlow-level.mdprotobuf-types.mdreads.mdtesting.mdtransactions.mdtypes.mdwrites.md
tile.json

tessl/golang-cloud-google-com--go--spanner

tessl install tessl/golang-cloud-google-com--go--spanner@1.87.2

Official Google Cloud Spanner client library for Go providing comprehensive database operations, transactions, and admin functionality

client.mddocs/

Client Management

This document covers creating, configuring, and managing Spanner clients including session pool configuration and client options.

Client Creation

Basic Client

Create a client with default configuration:

func NewClient(ctx context.Context, database string, opts ...option.ClientOption) (*Client, error)

Parameters:

  • ctx: Context for authentication and connection setup
  • database: Database name in format projects/PROJECT_ID/instances/INSTANCE_ID/databases/DATABASE_ID
  • opts: Optional client options (credentials, endpoints, etc.)

Example:

ctx := context.Background()
client, err := spanner.NewClient(ctx, "projects/my-project/instances/my-instance/databases/my-db")
if err != nil {
    log.Fatal(err)
}
defer client.Close()

Client with Custom Configuration

Create a client with custom session pool and query options:

func NewClientWithConfig(ctx context.Context, database string, config ClientConfig, opts ...option.ClientOption) (*Client, error)

Example:

config := spanner.ClientConfig{
    SessionPoolConfig: spanner.SessionPoolConfig{
        MinOpened:     50,
        MaxOpened:     200,
        MaxIdle:       20,
    },
    QueryOptions: spanner.QueryOptions{
        Priority: sppb.RequestOptions_PRIORITY_MEDIUM,
    },
}
client, err := spanner.NewClientWithConfig(ctx, database, config)
if err != nil {
    log.Fatal(err)
}
defer client.Close()

Multi-Endpoint Client

Create a client with multiple endpoint support for failover:

func NewMultiEndpointClient(ctx context.Context, database string, gmeCfg *grpcgcp.GCPMultiEndpointOptions, opts ...option.ClientOption) (*Client, *grpcgcp.GCPMultiEndpoint, error)

func NewMultiEndpointClientWithConfig(ctx context.Context, database string, config ClientConfig, gmeCfg *grpcgcp.GCPMultiEndpointOptions, opts ...option.ClientOption) (*Client, *grpcgcp.GCPMultiEndpoint, error)

These functions create a client with GCPMultiEndpoint support for:

  • Fallback to alternative endpoints when primary is unavailable
  • Route calls to specific endpoint groups
  • Runtime endpoint reconfiguration

Client Type

type Client struct {
    // Has unexported fields
}

The Client is safe for concurrent use and provides methods for reading, writing, and managing transactions.

Client Methods

// Data operations
func (c *Client) Single() *ReadOnlyTransaction
func (c *Client) ReadOnlyTransaction() *ReadOnlyTransaction
func (c *Client) ReadWriteTransaction(ctx context.Context, f func(context.Context, *ReadWriteTransaction) error) (commitTimestamp time.Time, err error)
func (c *Client) ReadWriteTransactionWithOptions(ctx context.Context, f func(context.Context, *ReadWriteTransaction) error, options TransactionOptions) (CommitResponse, error)

// Batch operations
func (c *Client) BatchReadOnlyTransaction(ctx context.Context, tb TimestampBound) (*BatchReadOnlyTransaction, error)
func (c *Client) BatchReadOnlyTransactionFromID(tid BatchReadOnlyTransactionID) *BatchReadOnlyTransaction
func (c *Client) BatchWrite(ctx context.Context, mgs []*MutationGroup) *BatchWriteResponseIterator
func (c *Client) BatchWriteWithOptions(ctx context.Context, mgs []*MutationGroup, opts BatchWriteOptions) *BatchWriteResponseIterator

// Write operations  
func (c *Client) Apply(ctx context.Context, ms []*Mutation, opts ...ApplyOption) (commitTimestamp time.Time, err error)
func (c *Client) PartitionedUpdate(ctx context.Context, statement Statement) (count int64, err error)
func (c *Client) PartitionedUpdateWithOptions(ctx context.Context, statement Statement, opts QueryOptions) (count int64, err error)

// Management
func (c *Client) Close()
func (c *Client) DatabaseName() string
func (c *Client) ClientID() string

Client lifecycle:

  • Always call Close() when done to release sessions
  • Use defer client.Close() to ensure cleanup
  • Clients are expensive to create - reuse when possible

ClientConfig

Complete configuration for client behavior:

type ClientConfig struct {
    // NumChannels is deprecated - use option.WithGRPCConnectionPool instead
    NumChannels int

    // Session pool configuration
    SessionPoolConfig SessionPoolConfig

    // Labels attached to all sessions created by this client
    SessionLabels map[string]string

    // Default query execution options
    QueryOptions QueryOptions

    // Default read operation options
    ReadOptions ReadOptions

    // Default apply operation options
    ApplyOptions []ApplyOption

    // Default transaction options
    TransactionOptions TransactionOptions

    // Default batch write options
    BatchWriteOptions BatchWriteOptions

    // Custom retry settings (overrides defaults)
    CallOptions *vkit.CallOptions

    // User agent prefix for tracking
    UserAgent string

    // Database role to assume for all operations
    DatabaseRole string

    // Disable routing read-write and PDML to leader region
    DisableRouteToLeader bool

    // Logger for client logging (nil uses standard logger)
    Logger *log.Logger

    // Compression for gRPC calls ("gzip" or "identity")
    Compression string

    // Timeout for batch session operations
    BatchTimeout time.Duration

    // Direct read options for replica/region routing
    DirectedReadOptions *sppb.DirectedReadOptions

    // OpenTelemetry meter provider
    OpenTelemetryMeterProvider metric.MeterProvider

    // Enable end-to-end tracing spans at Spanner layer
    EnableEndToEndTracing bool

    // Disable native metrics emission
    DisableNativeMetrics bool

    // Internal: experimental host flag
    IsExperimentalHost bool
}

SessionPoolConfig

Configuration for the client's session pool:

type SessionPoolConfig struct {
    // Maximum number of opened sessions (blocks when reached)
    // Default: NumChannels * 100
    MaxOpened uint64

    // Minimum number of sessions to maintain
    // Default: 100
    MinOpened uint64

    // Maximum number of idle sessions allowed
    // Default: 0
    MaxIdle uint64

    // MaxBurst is deprecated and no longer used
    MaxBurst uint64

    // WriteSessions is deprecated and no longer used
    WriteSessions float64

    // Number of workers for health checking
    // Default: 10
    HealthCheckWorkers int

    // Interval between health checks
    // Default: 50 minutes
    HealthCheckInterval time.Duration

    // Interval for checking multiplexed sessions
    // Default: 10 minutes
    MultiplexSessionCheckInterval time.Duration

    // Track stacktrace of goroutines taking sessions (debugging)
    // Default: false
    TrackSessionHandles bool

    // Configuration for inactive transaction handling
    InactiveTransactionRemovalOptions InactiveTransactionRemovalOptions
}

Default Session Pool Config:

var DefaultSessionPoolConfig = SessionPoolConfig{
    MinOpened:           100,
    MaxOpened:           numChannels * 100,
    MaxBurst:            10,
    WriteSessions:       0.2,
    HealthCheckWorkers:  10,
    HealthCheckInterval: 50 * time.Minute,
    InactiveTransactionRemovalOptions: InactiveTransactionRemovalOptions{
        ActionOnInactiveTransaction: Warn,
    },
}

Session Pool Example

config := spanner.ClientConfig{
    SessionPoolConfig: spanner.SessionPoolConfig{
        MinOpened:           50,   // Keep at least 50 sessions warm
        MaxOpened:           400,  // Allow up to 400 sessions
        MaxIdle:             50,   // Expire idle sessions beyond 50
        HealthCheckWorkers:  20,   // Use 20 workers for health checks
        HealthCheckInterval: 30 * time.Minute,
        TrackSessionHandles: true, // Enable for debugging leaks
    },
}

client, err := spanner.NewClientWithConfig(ctx, database, config)

InactiveTransactionRemovalOptions

Configuration for handling inactive transactions:

type InactiveTransactionRemovalOptions struct {
    // Action to take on inactive transactions
    ActionOnInactiveTransaction ActionOnInactiveTransactionKind
    
    // Has unexported fields for thresholds and frequencies
}

type ActionOnInactiveTransactionKind int

const (
    NoAction     ActionOnInactiveTransactionKind = iota  // No action
    Warn                                                  // Log inactive transactions
    Close                                                 // Close without logging
    WarnAndClose                                          // Log and close
)

QueryOptions

Default options for SQL queries and DML:

type QueryOptions struct {
    // Query execution mode
    Mode *sppb.ExecuteSqlRequest_QueryMode
    
    // Query optimizer options
    Options *sppb.ExecuteSqlRequest_QueryOptions
    
    // RPC priority for query execution
    Priority sppb.RequestOptions_Priority
    
    // Tag for tracking this request
    RequestTag string
    
    // Enable Data Boost for partitioned queries
    DataBoostEnabled bool
    
    // Direct read options for replica/region targeting
    DirectedReadOptions *sppb.DirectedReadOptions
    
    // Exclude partitioned update from change streams
    ExcludeTxnFromChangeStreams bool
    
    // Mark statement as last in transaction
    LastStatement bool
}

ReadOptions

Default options for read operations:

type ReadOptions struct {
    // Index to use for reading
    Index string
    
    // Maximum number of rows to read (0 = no limit)
    Limit int
    
    // RPC priority
    Priority sppb.RequestOptions_Priority
    
    // Request tag for tracking
    RequestTag string
    
    // Enable Data Boost for partitioned reads
    DataBoostEnabled bool
    
    // Direct read options for replica/region targeting
    DirectedReadOptions *sppb.DirectedReadOptions
    
    // Row ordering control
    OrderBy sppb.ReadRequest_OrderBy
    
    // Lock hint for read-write transactions
    LockHint sppb.ReadRequest_LockHint
}

TransactionOptions

Options for transaction execution:

type TransactionOptions struct {
    // Options for commit operation
    CommitOptions CommitOptions
    
    // Tag automatically included with all statements and commit
    TransactionTag string
    
    // Priority for the Commit RPC
    CommitPriority sppb.RequestOptions_Priority
    
    // Read lock mode for read/write transactions
    ReadLockMode sppb.TransactionOptions_ReadWrite_ReadLockMode
    
    // Exclude transaction from change streams
    ExcludeTxnFromChangeStreams bool
    
    // Isolation level for read/write transaction
    IsolationLevel sppb.TransactionOptions_IsolationLevel
    
    // Controls BeginTransaction RPC behavior
    BeginTransactionOption BeginTransactionOption
}

type BeginTransactionOption int

const (
    // Use default for transaction type
    DefaultBeginTransaction BeginTransactionOption = iota
    
    // Include BeginTransaction with first statement (default for RW)
    InlinedBeginTransaction
    
    // Use separate BeginTransaction RPC (default for RO and stmt-based)
    ExplicitBeginTransaction
)

CommitOptions

Options for committing transactions:

type CommitOptions struct {
    // Request commit statistics in response
    ReturnCommitStats bool
    
    // Maximum delay before commit (for latency optimization)
    MaxCommitDelay *time.Duration
}

BatchWriteOptions

Options for batch write operations:

type BatchWriteOptions struct {
    // RPC priority for batch write
    Priority sppb.RequestOptions_Priority
    
    // Transaction tag for all transactions in batch
    TransactionTag string
    
    // Exclude all transactions from change streams
    ExcludeTxnFromChangeStreams bool
}

Client Options (google.golang.org/api/option)

Standard Google API client options can be passed to client constructors:

import "google.golang.org/api/option"

// Custom credentials
client, err := spanner.NewClient(ctx, database,
    option.WithCredentialsFile("/path/to/credentials.json"))

// Custom endpoint
client, err := spanner.NewClient(ctx, database,
    option.WithEndpoint("custom-endpoint:443"))

// gRPC connection pool
client, err := spanner.NewClient(ctx, database,
    option.WithGRPCConnectionPool(8))

// Disable authentication (for emulator)
client, err := spanner.NewClient(ctx, database,
    option.WithoutAuthentication())

Advanced Configuration Examples

High-Throughput Configuration

For high-throughput workloads:

config := spanner.ClientConfig{
    SessionPoolConfig: spanner.SessionPoolConfig{
        MinOpened:     200,
        MaxOpened:     1000,
        MaxIdle:       100,
        HealthCheckWorkers: 50,
    },
    QueryOptions: spanner.QueryOptions{
        Priority: sppb.RequestOptions_PRIORITY_HIGH,
    },
    Compression: "gzip",
}

client, err := spanner.NewClientWithConfig(ctx, database, config,
    option.WithGRPCConnectionPool(16))

Read-Heavy Configuration

For read-heavy workloads with stale reads:

config := spanner.ClientConfig{
    SessionPoolConfig: spanner.SessionPoolConfig{
        MinOpened: 100,
        MaxOpened: 500,
        MaxIdle:   50,
    },
    ReadOptions: spanner.ReadOptions{
        Priority: sppb.RequestOptions_PRIORITY_MEDIUM,
    },
    DisableRouteToLeader: true,  // Allow reads from replicas
}

client, err := spanner.NewClientWithConfig(ctx, database, config)

Debug Configuration

For debugging session leaks:

config := spanner.ClientConfig{
    SessionPoolConfig: spanner.SessionPoolConfig{
        MinOpened: 10,
        MaxOpened: 50,
        TrackSessionHandles: true,  // Track goroutines
    },
    Logger: log.New(os.Stdout, "spanner: ", log.LstdFlags),
}

client, err := spanner.NewClientWithConfig(ctx, database, config)

Multi-Region with Directed Reads

Direct reads to specific regions:

directedReadOptions := &sppb.DirectedReadOptions{
    Replicas: &sppb.DirectedReadOptions_IncludeReplicas_{
        IncludeReplicas: &sppb.DirectedReadOptions_IncludeReplicas{
            ReplicaSelections: []*sppb.DirectedReadOptions_ReplicaSelection{
                {
                    Location: "us-central1",
                    Type:     sppb.DirectedReadOptions_ReplicaSelection_READ_ONLY,
                },
            },
        },
    },
}

config := spanner.ClientConfig{
    DirectedReadOptions: directedReadOptions,
}

client, err := spanner.NewClientWithConfig(ctx, database, config)

Database Role Assignment

Assume a specific database role for all operations:

config := spanner.ClientConfig{
    DatabaseRole: "reporting_role",
}

client, err := spanner.NewClientWithConfig(ctx, database, config)
// All operations use reporting_role permissions

Observability Configuration

Enable OpenTelemetry Metrics

func EnableOpenTelemetryMetrics()
func IsOpenTelemetryMetricsEnabled() bool

Enable before creating clients:

spanner.EnableOpenTelemetryMetrics()

// Configure meter provider
config := spanner.ClientConfig{
    OpenTelemetryMeterProvider: myMeterProvider,
    EnableEndToEndTracing:     true,
}

client, err := spanner.NewClientWithConfig(ctx, database, config)

Session Pool Metrics (OpenCensus - Deprecated)

These functions are deprecated - use OpenTelemetry instead:

func EnableStatViews() error
func EnableGfeLatencyView() error
func EnableGfeHeaderMissingCountView() error
func EnableGfeLatencyAndHeaderMissingCountViews() error
func DisableGfeLatencyAndHeaderMissingCountViews()

Best Practices

  1. Reuse Clients: Create once, reuse for application lifetime
  2. Always Close: Use defer client.Close() to avoid session leaks
  3. Size Session Pool: Based on concurrent operations needed
  4. Monitor Sessions: Enable metrics in production
  5. Set Appropriate Timeouts: Use context deadlines for operations
  6. Use Connection Pools: Increase gRPC connections for high throughput
  7. Enable Compression: For large payloads over slow networks
  8. Track Session Handles: Enable temporarily to debug leaks
  9. Configure Health Checks: Adjust frequency based on workload
  10. Use Database Roles: For fine-grained access control

Common Patterns

Shared Client

var client *spanner.Client

func init() {
    ctx := context.Background()
    var err error
    client, err = spanner.NewClient(ctx, database)
    if err != nil {
        log.Fatal(err)
    }
}

func main() {
    defer client.Close()
    // Use client throughout application
}

Client with Context Timeout

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

client, err := spanner.NewClient(ctx, database)
if err != nil {
    log.Fatal(err)
}
defer client.Close()

Client for Testing

import "os"

os.Setenv("SPANNER_EMULATOR_HOST", "localhost:9010")

client, err := spanner.NewClient(ctx, "projects/test/instances/test/databases/test")
// Client automatically connects to emulator