errorsbp

package
v0.4.2 Latest Latest
Warning

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

Go to latest
Published: Jul 7, 2020 License: BSD-3-Clause Imports: 3 Imported by: 0

Documentation

Overview

Package errorsbp provides some error utilities for Baseplate.go project.

Batch

errorsbp.Batch can be used to compile multiple errors into a single one.

An example of how to use it in your functions:

type worker func() error

func runWorksParallel(works []worker) error {
    errChan := make(chan error, len(works))
    var wg sync.WaitGroup
    wg.Add(len(works))

    for _, work := range works {
        go func(work worker) {
            defer wg.Done()
            errChan <- work()
        }(work)
    }

    wg.Wait()
    var batch errorsbp.Batch
    for err := range errChan {
        // nil errors will be auto skipped
        batch.Add(err)
    }
    // If all works succeeded, Compile() returns nil.
    // If only one work failed, Compile() returns that error directly
    // instead of wrapping it inside BatchError.
    return batch.Compile()
}

errorsbp.Batch is not thread-safe. The same batch should not be operated on different goroutines concurrently.

Suppressor

Suppressor is a type defined to provide an unified way to allow certain functions/features to ignore certain errors.

It's currently used by thriftbp package in both server and client middlewares, to not treat certain errors defined in thrift IDL as span errors. Because of go's type system, we cannot provide a Suppressor implementation to suppress all errors defined in all thrift IDLs, as a result we rely on service/client implementations to implement it for the middlewares.

An example of how to implement it for your thrift defined errors:

func MyThriftSuppressor(err error) bool {
    return errors.As(err, new(*mythrift.MyThriftErrorType))
}
Example
package main

import (
	"errors"
	"fmt"

	"github.com/reddit/baseplate.go/errorsbp"
)

func main() {
	var batch errorsbp.Batch

	var singleError error = batch.Compile()
	fmt.Printf("0: %v\n", singleError)

	err := errors.New("foo")
	batch.Add(err)
	singleError = batch.Compile()
	fmt.Printf("1: %v\n", singleError)

	batch.Add(nil)
	singleError = batch.Compile()
	fmt.Printf("Nil errors are skipped: %v\n", singleError)

	err = errors.New("bar")
	batch.Add(err)
	singleError = batch.Compile()
	fmt.Printf("2: %v\n", singleError)

	var newBatch errorsbp.Batch
	// Add multiple errors at once
	newBatch.Add(
		errors.New("fizz"),
		errors.New("buzz"),
	)
	newBatch.Add(batch)
	fmt.Printf("3: %v\n", newBatch.Compile())

}
Output:

0: <nil>
1: foo
Nil errors are skipped: foo
2: errorsbp.Batch: total 2 error(s) in this batch: foo; bar
3: errorsbp.Batch: total 4 error(s) in this batch: fizz; buzz; foo; bar

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func SuppressNone

func SuppressNone(err error) bool

SuppressNone is a Suppressor implementation that always return false, thus suppress none of the errors.

It's the default implementation nil Suppressor falls back into.

Types

type Batch

type Batch struct {
	// contains filtered or unexported fields
}

Batch is an error that can contain multiple errors.

The zero value of Batch is valid (with no errors) and ready to use.

This type is not thread-safe. The same batch should not be operated on different goroutines concurrently.

func (*Batch) Add

func (be *Batch) Add(errs ...error)

Add adds errors into the batch.

If an error is also an Batch, its underlying error(s) will be added instead of the Batch itself.

Nil errors will be skipped.

func (Batch) As

func (be Batch) As(v interface{}) bool

As implements helper interface for errors.As.

If v is pointer to either Batch or *Batch, *v will be set into this error. Otherwise, As will try errors.As against all errors in this batch, returning the first match.

See Is for the discussion of possiblity of infinite loop.

Example

This example demonstrates how a BatchError can be inspected with errors.As.

package main

import (
	"context"
	"errors"
	"fmt"
	"os"

	"github.com/reddit/baseplate.go/errorsbp"
)

func main() {
	var batch errorsbp.Batch
	var target *os.PathError

	batch.Add(context.Canceled)
	err := batch.Compile()
	fmt.Println(errors.As(err, &target)) // false

	batch.Add(fmt.Errorf("wrapped: %w", &os.PathError{}))
	err = batch.Compile()
	fmt.Println(errors.As(err, &target)) // true

	batch.Add(fmt.Errorf("wrapped: %w", &os.LinkError{}))
	err = batch.Compile()
	fmt.Println(errors.As(err, &target)) // true

}
Output:

false
true
true

func (*Batch) Clear

func (be *Batch) Clear()

Clear clears the batch.

func (Batch) Compile

func (be Batch) Compile() error

Compile compiles the batch.

If the batch contains zero errors, Compile returns nil.

If the batch contains exactly one error, that underlying error will be returned.

Otherwise, the batch itself will be returned.

func (Batch) Error

func (be Batch) Error() string

func (Batch) GetErrors

func (be Batch) GetErrors() []error

GetErrors returns a copy of the underlying error(s).

func (Batch) Is

func (be Batch) Is(target error) bool

Is implements helper interface for errors.Is.

It calls errors.Is against all errors in this batch, until a match is found.

If an error in the batch is the Batch itself, calling its Is (and As) could cause an infinite loop. But there's a special handling in Add function, that if you try to add a Batch into the batch, we add the underlying errors instead the Batch itself. As a result it should be impossible to cause infinite loops in Is and As.

Example

This example demonstrates how a BatchError can be inspected with errors.Is.

package main

import (
	"context"
	"errors"
	"fmt"
	"io"

	"github.com/reddit/baseplate.go/errorsbp"
)

func main() {
	var batch errorsbp.Batch

	batch.Add(context.Canceled)
	err := batch.Compile()
	fmt.Println(errors.Is(err, context.Canceled)) // true
	fmt.Println(errors.Is(err, io.EOF))           // false

	batch.Add(fmt.Errorf("wrapped: %w", io.EOF))
	err = batch.Compile()
	fmt.Println(errors.Is(err, context.Canceled)) // true
	fmt.Println(errors.Is(err, io.EOF))           // true

}
Output:

true
false
true
true

type Suppressor

type Suppressor func(err error) bool

Suppressor defines a type of function can be used to suppress certain errors.

The implementation shall return true on the errors they want to suppress, and false on all other errors.

Example

This example demonstrates how to implement a Suppressor.

package main

import (
	"errors"

	"github.com/reddit/baseplate.go/errorsbp"
	"github.com/reddit/baseplate.go/internal/gen-go/reddit/baseplate"
)

// BEGIN THRIFT GENERATED CODE
//
// In real code this part should come from thrift compiled go code.
// Here we just write some placeholders to use as an example.

type MyThriftException struct{}

func (*MyThriftException) Error() string {
	return "my thrift exception"
}

// END THRIFT GENERATED CODE

func MyThriftExceptionSuppressor(err error) bool {
	return errors.As(err, new(*MyThriftException))
}

func BaseplateErrorSuppressor(err error) bool {
	// baseplate.Error is from a thrift exception defined in baspleate.thrift,
	// then compiled to go code by thrift compiler.
	// We use that type as an example here.
	// In real code you usually also should add (Or) additional exceptions defined
	// in your thrift files.
	return errors.As(err, new(*baseplate.Error))
}

// This example demonstrates how to implement a Suppressor.
func main() {
	// This constructs the Suppressor you could fill into
	// thriftbp.ServerConfig.ErrorSpanSuppressor field.
	errorsbp.OrSuppressors(BaseplateErrorSuppressor, MyThriftExceptionSuppressor)
}

func OrSuppressors

func OrSuppressors(suppressors ...Suppressor) Suppressor

OrSuppressors combines the given suppressors.

If any of the suppressors return true on an error, the combined Suppressor would returns true on that error.

func (Suppressor) Suppress

func (s Suppressor) Suppress(err error) bool

Suppress is the nil-safe way of calling a Suppressor.

func (Suppressor) Wrap

func (s Suppressor) Wrap(err error) error

Wrap wraps the error based on the decision of Suppressor.

If the error shall be suppressed, Wrap returns nil. Otherwise Wrap returns the error as-is.

Like Suppress, Wrap is also nil-safe.

Jump to

Keyboard shortcuts

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