Skip to content

Configurable error handler for terminal errors #128

Description

@jacobdrury

In the typescript sdk there is a concept of a asTerminalError func that can be defined on the service individually or directly on the endpoint: https://restatedev.github.io/sdk-typescript/types/_restatedev_restate-sdk.ServiceOptions.html#asterminalerror

It would be great if we could add a similar error handling func to the go sdk.

Would love some input for how this should be added to the sdk so that I can follow this up with a PR! I put some of my ideas below:

My use-case would be when initializing the restate server so being able to provide the error handler function somewhat like below would achieve what I'm going for:

func main() {
	server := server.NewRestate().
		WithErrorHandler(func(err error) error {
			// If the error is already a terminal error, return it
			if restate.IsTerminalError(err) {
				return err
			}

			// If the error is a context deadline exceeded, return a terminal error
			if errors.Is(err, context.DeadlineExceeded) {
				return restate.TerminalError(err)
			}

			// Otherwise return the error as is
			return err
		}).
		// Handlers can be inferred from object methods
		Bind(restate.Reflect(Greeter{})).
		Bind(restate.Reflect(GreeterCounter{}))

	if err := server.Start(context.Background(), ":9080"); err != nil {
		slog.Error("application exited unexpectedly", "err", err.Error())
		os.Exit(1)
	}
}

If we wanted each service to be able to define their own error handling logic, there could be an interface they implement that could take precedence over the global error handle

type serviceErrorHandler interface {
	HandleError(err error) error
}

We also could allow this error handler func to be passed into restate.Run as an option if we want to override any of the previous error handling:

_, err = restate.Run(ctx, func(ctx restate.RunContext) (bool, error) {
	log := ctx.Log().With("uuid", uuid, "price", price)
	if rand.Float64() < 0.5 {
		log.Info("payment succeeded")
		return true, nil
	} else {
		log.Error("payment failed")
		return false, fmt.Errorf("failed to pay")
	}
}, restate.WithErrorHandler(func(err error) error {
	// If the error is already a terminal error, return it
	if restate.IsTerminalError(err) {
		return err
	}

	// If the error is a context deadline exceeded, return a terminal error
	if errors.Is(err, context.DeadlineExceeded) {
		return restate.TerminalError(err)
	}

	// Otherwise return the error as is
	return err
}))

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions