gax

package module
v2.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 23, 2021 License: BSD-3-Clause Imports: 9 Imported by: 963

Documentation

Overview

Package gax contains a set of modules which aid the development of APIs for clients and servers based on gRPC and Google API conventions.

Application code will rarely need to use this library directly. However, code generated automatically from API definition files can use it to simplify code generation and to provide more convenient and idiomatic API surfaces.

Index

Examples

Constants

View Source
const Version = "2.0.5"

Version specifies the gax-go version being used.

Variables

This section is empty.

Functions

func Invoke

func Invoke(ctx context.Context, call APICall, opts ...CallOption) error

Invoke calls the given APICall, performing retries as specified by opts, if any.

func Sleep

func Sleep(ctx context.Context, d time.Duration) error

Sleep is similar to time.Sleep, but it can be interrupted by ctx.Done() closing. If interrupted, Sleep returns ctx.Err().

func XGoogHeader

func XGoogHeader(keyval ...string) string

XGoogHeader is for use by the Google Cloud Libraries only.

XGoogHeader formats key-value pairs. The resulting string is suitable for x-goog-api-client header.

Types

type APICall

type APICall func(context.Context, CallSettings) error

APICall is a user defined call stub.

type Backoff

type Backoff struct {
	// Initial is the initial value of the retry period, defaults to 1 second.
	Initial time.Duration

	// Max is the maximum value of the retry period, defaults to 30 seconds.
	Max time.Duration

	// Multiplier is the factor by which the retry period increases.
	// It should be greater than 1 and defaults to 2.
	Multiplier float64
	// contains filtered or unexported fields
}

Backoff implements exponential backoff. The wait time between retries is a random value between 0 and the "retry period" - the time between retries. The retry period starts at Initial and increases by the factor of Multiplier every retry, but is capped at Max.

Note: MaxNumRetries / RPCDeadline is specifically not provided. These should be built on top of Backoff.

Example
package main

import (
	"context"
	"net/http"
	"time"

	gax "github.com/googleapis/gax-go/v2"
)

func main() {
	ctx := context.Background()

	bo := gax.Backoff{
		Initial:    time.Second,
		Max:        time.Minute, // Maximum amount of time between retries.
		Multiplier: 2,
	}

	performHTTPCallWithRetry := func(ctx context.Context, doHTTPCall func(ctx context.Context) (*http.Response, error)) (*http.Response, error) {
		for {
			resp, err := doHTTPCall(ctx)
			if err != nil {
				// Retry 503 UNAVAILABLE.
				if resp.StatusCode == http.StatusServiceUnavailable {
					if err := gax.Sleep(ctx, bo.Pause()); err != nil {
						return nil, err
					}
					continue
				}
				return nil, err
			}
			return resp, err
		}
	}

	// It's recommended to set deadlines on HTTP calls and around retrying. This
	// is also usually preferred over setting some fixed number of retries: one
	// advantage this has is that backoff settings can be changed independently
	// of the deadline, whereas with a fixed number of retries the deadline
	// would be a constantly-shifting goalpost.
	ctxWithTimeout, cancel := context.WithDeadline(ctx, time.Now().Add(5*time.Minute))
	defer cancel()

	resp, err := performHTTPCallWithRetry(ctxWithTimeout, func(ctx context.Context) (*http.Response, error) {
		req, err := http.NewRequest("some-method", "example.com", nil)
		if err != nil {
			return nil, err
		}
		req = req.WithContext(ctx)
		return http.DefaultClient.Do(req)
	})
	if err != nil {
		// TODO: handle err
	}
	_ = resp // TODO: use resp if err is nil
}
Output:

func (*Backoff) Pause

func (bo *Backoff) Pause() time.Duration

Pause returns the next time.Duration that the caller should use to backoff.

type CallOption

type CallOption interface {
	// Resolve applies the option by modifying cs.
	Resolve(cs *CallSettings)
}

CallOption is an option used by Invoke to control behaviors of RPC calls. CallOption works by modifying relevant fields of CallSettings.

func WithGRPCOptions

func WithGRPCOptions(opt ...grpc.CallOption) CallOption

WithGRPCOptions allows passing gRPC call options during client creation.

func WithRetry

func WithRetry(fn func() Retryer) CallOption

WithRetry sets CallSettings.Retry to fn.

type CallSettings

type CallSettings struct {
	// Retry returns a Retryer to be used to control retry logic of a method call.
	// If Retry is nil or the returned Retryer is nil, the call will not be retried.
	Retry func() Retryer

	// CallOptions to be forwarded to GRPC.
	GRPC []grpc.CallOption
}

CallSettings allow fine-grained control over how calls are made.

type Retryer

type Retryer interface {
	// Retry reports whether a request should be retried and how long to pause before retrying
	// if the previous attempt returned with err. Invoke never calls Retry with nil error.
	Retry(err error) (pause time.Duration, shouldRetry bool)
}

Retryer is used by Invoke to determine retry behavior.

func OnCodes

func OnCodes(cc []codes.Code, bo Backoff) Retryer

OnCodes returns a Retryer that retries if and only if the previous attempt returns a GRPC error whose error code is stored in cc. Pause times between retries are specified by bo.

bo is only used for its parameters; each Retryer has its own copy.

Example
package main

import (
	"context"
	"time"

	gax "github.com/googleapis/gax-go/v2"
	"google.golang.org/grpc/codes"
)

// Some result that the client might return.
type fakeResponse struct{}

// Some client that can perform RPCs.
type fakeClient struct{}

// PerformSomeRPC is a fake RPC that a client might perform.
func (c *fakeClient) PerformSomeRPC(ctx context.Context) (*fakeResponse, error) {

	return nil, nil
}

func main() {
	ctx := context.Background()
	c := &fakeClient{}

	// UNKNOWN and UNAVAILABLE are typically safe to retry for idempotent RPCs.
	retryer := gax.OnCodes([]codes.Code{codes.Unknown, codes.Unavailable}, gax.Backoff{
		Initial:    time.Second,
		Max:        32 * time.Second,
		Multiplier: 2,
	})

	performSomeRPCWithRetry := func(ctx context.Context) (*fakeResponse, error) {
		for {
			resp, err := c.PerformSomeRPC(ctx)
			if err != nil {
				if delay, shouldRetry := retryer.Retry(err); shouldRetry {
					if err := gax.Sleep(ctx, delay); err != nil {
						return nil, err
					}
					continue
				}
				return nil, err
			}
			return resp, err
		}
	}

	// It's recommended to set deadlines on RPCs and around retrying. This is
	// also usually preferred over setting some fixed number of retries: one
	// advantage this has is that backoff settings can be changed independently
	// of the deadline, whereas with a fixed number of retries the deadline
	// would be a constantly-shifting goalpost.
	ctxWithTimeout, cancel := context.WithDeadline(ctx, time.Now().Add(5*time.Minute))
	defer cancel()

	resp, err := performSomeRPCWithRetry(ctxWithTimeout)
	if err != nil {
		// TODO: handle err
	}
	_ = resp // TODO: use resp if err is nil
}
Output:

func OnErrorFunc added in v2.1.0

func OnErrorFunc(bo Backoff, shouldRetry func(err error) bool) Retryer

OnErrorFunc returns a Retryer that retries if and only if the previous attempt returns an error that satisfies shouldRetry.

Pause times between retries are specified by bo. bo is only used for its parameters; each Retryer has its own copy.

Example
package main

import (
	"context"
	"time"

	gax "github.com/googleapis/gax-go/v2"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

// Some result that the client might return.
type fakeResponse struct{}

// Some client that can perform RPCs.
type fakeClient struct{}

// PerformSomeRPC is a fake RPC that a client might perform.
func (c *fakeClient) PerformSomeRPC(ctx context.Context) (*fakeResponse, error) {

	return nil, nil
}

func main() {
	ctx := context.Background()
	c := &fakeClient{}

	shouldRetryUnavailableUnKnown := func(err error) bool {
		st, ok := status.FromError(err)
		if !ok {
			return false
		}

		return st.Code() == codes.Unavailable || st.Code() == codes.Unknown
	}
	retryer := gax.OnErrorFunc(gax.Backoff{
		Initial:    time.Second,
		Max:        32 * time.Second,
		Multiplier: 2,
	}, shouldRetryUnavailableUnKnown)

	performSomeRPCWithRetry := func(ctx context.Context) (*fakeResponse, error) {
		for {
			resp, err := c.PerformSomeRPC(ctx)
			if err != nil {
				if delay, shouldRetry := retryer.Retry(err); shouldRetry {
					if err := gax.Sleep(ctx, delay); err != nil {
						return nil, err
					}
					continue
				}
				return nil, err
			}
			return resp, err
		}
	}

	// It's recommended to set deadlines on RPCs and around retrying. This is
	// also usually preferred over setting some fixed number of retries: one
	// advantage this has is that backoff settings can be changed independently
	// of the deadline, whereas with a fixed number of retries the deadline
	// would be a constantly-shifting goalpost.
	ctxWithTimeout, cancel := context.WithDeadline(ctx, time.Now().Add(5*time.Minute))
	defer cancel()

	resp, err := performSomeRPCWithRetry(ctxWithTimeout)
	if err != nil {
		// TODO: handle err
	}
	_ = resp // TODO: use resp if err is nil
}
Output:

Directories

Path Synopsis
Package apierror implements a wrapper error for parsing error details from API calls.
Package apierror implements a wrapper error for parsing error details from API calls.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL