Beispiel #1
0
func runOnce(ctx context.Context, f func(context.Context) error) error {
	req := &pb.BeginTransactionRequest{}
	resp := &pb.BeginTransactionResponse{}
	if err := call(ctx, "beginTransaction", req, resp); err != nil {
		return err
	}
	subCtx := context.WithValue(ctx, ContextKey("transaction"), resp.Transaction)
	finished := false
	// Call f, rolling back the transaction if f returns a non-nil error, or panics.
	// The panic is not recovered.
	defer func() {
		if finished {
			return
		}
		finished = true
		// Ignore the error return value, since we are already returning a non-nil
		// error (or we're panicking).
		call(subCtx, "rollback", &pb.RollbackRequest{Transaction: resp.Transaction}, &pb.RollbackResponse{})
	}()
	if err := f(subCtx); err != nil {
		return err
	}
	finished = true
	err := call(subCtx, "commit", &pb.CommitRequest{Transaction: resp.Transaction}, &pb.CommitResponse{})
	if e, ok := err.(*errHTTP); ok && e.StatusCode == http.StatusConflict {
		// TODO(jbd): Make sure that we explicitly handle the case where response
		// has an HTTP 409 and the error message indicates that it's an concurrent
		// transaction error.
		return ErrConcurrentTransaction
	}
	return err
}
Beispiel #2
0
func WithContext(parent context.Context, projID string, c *http.Client) context.Context {
	if c == nil {
		panic("nil *http.Client passed to WithContext")
	}
	if projID == "" {
		panic("empty project ID passed to WithContext")
	}
	return context.WithValue(parent, contextKey{}, &cloudContext{
		ProjectID:  projID,
		HTTPClient: c,
	})
}
Beispiel #3
0
// WithNamespace returns a new context that limits the scope its parent
// context with a Datastore namespace.
func WithNamespace(parent context.Context, namespace string) context.Context {
	return context.WithValue(parent, nsKey{}, namespace)
}