Skip to content

Commit

Permalink
Expose and explain RegisterTypeMigration().
Browse files Browse the repository at this point in the history
  • Loading branch information
knz committed Oct 29, 2020
1 parent 102bafb commit b33d88a
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 0 deletions.
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,28 @@ proposal](https://go.googlesource.com/proposal/+/master/design/29934-error-value
printing out error details, and knows how to present a chain of
causes in a semi-structured format upon formatting with `%+v`.

### Ensuring `errors.Is` works when packages are renamed

If a Go package containing a custom error type is renamed, or the
error type itself is renamed, and errors of this type are transported
over the network, then another system with a different code layout
(e.g. running a different version of the software) may not be able to
recognize the error any more via `errors.Is`.

To ensure that network portability continues to work across multiple
software versions, in the case error types get renamed or Go packages
get moved / renamed / etc, the server code must call
`errors.RegisterTypeMigration()` from e.g. an `init()` function.

Example use:

```go
previousPath := "github.com/old/path/to/error/package"
previousTypeName := "oldpackage.oldErrorName"
newErrorInstance := &newTypeName{...}
errors.RegisterTypeMigration(previousPath, previousTypeName, newErrorInstance)
```

## Error composition (summary)

| Constructor | Composes |
Expand Down Expand Up @@ -552,6 +574,9 @@ type LeafDecoder = func(ctx context.Context, msg string, safeDetails []string, p
type WrapperEncoder = func(ctx context.Context, err error) (msgPrefix string, safeDetails []string, payload proto.Message)
type WrapperDecoder = func(ctx context.Context, cause error, msgPrefix string, safeDetails []string, payload proto.Message) error
// Registering package renames for custom error types.
func RegisterTypeMigration(previousPkgPath, previousTypeName string, newType error)
// Sentry reports.
func BuildSentryReport(err error) (*sentry.Event, map[string]interface{})
func ReportError(err error) (string)
Expand Down
24 changes: 24 additions & 0 deletions errbase_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,27 @@ func FormatError(err error, s fmt.State, verb rune) { errbase.FormatError(err, s
// will provide "smart" formatting even if the outer layer
// of the error does not implement the Formatter interface.
func Formattable(err error) fmt.Formatter { return errbase.Formattable(err) }

// RegisterTypeMigration tells the library that the type of the error
// given as 3rd argument was previously known with type
// previousTypeName, located at previousPkgPath.
//
// The value of previousTypeName must be the result of calling
// reflect.TypeOf(err).String() on the original error object.
// This is usually composed as follows:
// [*]<shortpackage>.<errortype>
//
// For example, Go's standard error type has name "*errors.errorString".
// The asterisk indicates that `errorString` implements the `error`
// interface via pointer receiver.
//
// Meanwhile, the singleton error type context.DeadlineExceeded
// has name "context.deadlineExceededError", without asterisk
// because the type implements `error` by value.
//
// Remember that the short package name inside the error type name and
// the last component of the package path can be different. This is
// why they must be specified separately.
func RegisterTypeMigration(previousPkgPath, previousTypeName string, newType error) {
errbase.RegisterTypeMigration(previousPkgPath, previousTypeName, newType)
}

0 comments on commit b33d88a

Please sign in to comment.