Skip to content
Dispatch Dispatch Dispatch
Go - Error handling

Error handling

Dispatch retries the execution of a function whenever a failure occurs, whether it’s an exception, a loss of connection or power outage. However, not all failures are the same, so you might want to teach Dispatch how to handle exceptions specific to your application.

Temporary errors

When error is temporary, tell Dispatch that it’s safe to retry that function until it succeeds. For example, when application is in maintenance mode, tell Dispatch to retry the function until application is back up again. To treat an error as temporary, implement an interface { Temporary() bool } interface for that error.

package main
import (
"context"
"log"
"github.com/dispatchrun/dispatch-go"
)
type MaintenanceError struct{}
func (error *MaintenanceError) Error() string {
return "server is under maintenance"
}
func (error *MaintenanceError) Temporary() bool {
return true
}
func main() {
calls := 0
notifyUser := dispatch.Func("notifyUser", func(ctx context.Context, userId string) (any, error) {
is_maintenance_on := calls < 2
calls++
if is_maintenance_on {
return nil, &MaintenanceError{}
}
// Send an email notification to the user
return nil, nil
})
endpoint, err := dispatch.New(notifyUser)
if err != nil {
log.Fatal(err)
}
go func() {
if _, err := notifyUser.Dispatch(context.Background(), "user_123"); err != nil {
log.Fatal(err)
}
}()
if err := endpoint.ListenAndServe(); err != nil {
log.Fatal(err)
}
}

When Temporary method of an error returns true, Dispatch treats it as a temporary error and retries the function that returns it. In the example above, the notifyUser function is in maintanence mode for the first two calls and succeeds on the third one.

Permanent errors

When error is fatal, retrying doesn’t make sense, because the function will keep running into it. Dispatch stops retrying a function when error’s Temporary method returns true.

For example, the user we wanted to send email to is now deactivated.

package main
import (
"context"
"log"
"github.com/dispatchrun/dispatch-go"
)
type UserDeactivatedError struct{}
func (error *UserDeactivatedError) Error() string {
return "user is deactivated"
}
func (error *UserDeactivatedError) Temporary() bool {
return false
}
func main() {
notifyUser := dispatch.Func("notifyUser", func(ctx context.Context, userId string) (any, error) {
if userId == "user_123" {
return nil, &UserDeactivatedError{}
}
// Send an email notification to the user
return nil, nil
})
endpoint, err := dispatch.New(notifyUser)
if err != nil {
log.Fatal(err)
}
go func() {
if _, err := notifyUser.Dispatch(context.Background(), "user_123"); err != nil {
log.Fatal(err)
}
}()
if err := endpoint.ListenAndServe(); err != nil {
log.Fatal(err)
}
}

Built-in Go errors

Dispatch recognizes the most common Go errors out of the box and determines whether it’s safe to retry the function call.

Go errorDispatch status
context.Canceleddispatch.ErrTemporary
context.DeadlineExceededdispatch.ErrTimeout
fs.ErrInvaliddispatch.ErrInvalidArgument
fs.ErrPermissiondispatch.ErrPermissionDenied
fs.ErrNotExistdispatch.ErrNotFound
fs.ErrCloseddispatch.ErrTemporary
net.ErrCloseddispatch.ErrTemporary
http.ErrNotSupporteddispatch.ErrHTTP
http.ErrMissingBoundarydispatch.ErrHTTP
http.ErrNotMultipartdispatch.ErrHTTP
net.DNSErrordispatch.ErrDNS
tls.CertificateVerificationErrordispatch.ErrTLS
tls.RecordHeaderErrordispatch.ErrTLS
unix.Errno == unix.ECONNREFUSEDdispatch.ErrTCP
unix.Errno == unix.ECONNRESETdispatch.ErrTCP
unix.Errno == unix.ECONNABORTEDdispatch.ErrTCP
unix.Errno == unix.EPIPEdispatch.ErrTCP
unix.Errno == unix.ENETDOWNdispatch.ErrTCP
unix.Errno == unix.ENETUNREACHdispatch.ErrTCP
unix.Errno == unix.ENETRESETdispatch.ErrTCP
unix.Errno == unix.EHOSTDOWNdispatch.ErrTCP
unix.Errno == unix.EHOSTUNREACHdispatch.ErrTCP
unix.Errno == unix.EADDRNOTAVAILdispatch.ErrTCP
unix.Errno == unix.ETIMEDOUTdispatch.ErrTimeout
unix.Errno == unix.EPERMdispatch.ErrPermissionDenied
unix.Errno == unix.EAGAINdispatch.ErrTemporary
unix.Errno == unix.EINTRdispatch.ErrTemporary
unix.Errno == unix.EMFILEdispatch.ErrTemporary
unix.Errno == unix.ENFILEdispatch.ErrTemporary
unix.Errnodispatch.ErrPermanent
connect.Error.Code() == connect.CodeCanceleddispatch.ErrTimeout
connect.Error.Code() == connect.CodeUnknowndispatch.ErrTemporary
connect.Error.Code() == connect.CodeInvalidArgumentdispatch.ErrInvalidArgument
connect.Error.Code() == connect.CodeDeadlineExceededdispatch.ErrTimeout
connect.Error.Code() == connect.CodeNotFounddispatch.ErrNotFound
connect.Error.Code() == connect.CodeAlreadyExistsdispatch.ErrPermanent
connect.Error.Code() == connect.CodePermissionDenieddispatch.ErrPermissionDenied
connect.Error.Code() == connect.CodeResourceExhausteddispatch.ErrThrottled
connect.Error.Code() == connect.CodeFailedPreconditiondispatch.ErrPermanent
connect.Error.Code() == connect.CodeAborteddispatch.ErrPermanent
connect.Error.Code() == connect.CodeOutOfRangedispatch.ErrInvalidArgument
connect.Error.Code() == connect.CodeUnimplementeddispatch.ErrNotFound
connect.Error.Code() == connect.CodeInternaldispatch.ErrTemporary
connect.Error.Code() == connect.CodeUnavailabledispatch.ErrTemporary
connect.Error.Code() == connect.CodeDataLossdispatch.ErrPermanent
connect.Error.Code() == connect.CodeUnauthenticateddispatch.ErrUnauthenticated
connect.Errordispatch.ErrPermanent
io.EOFdispatch.ErrTemporary
io.ErrClosedPipedispatch.ErrTemporary
io.ErrNoProgressdispatch.ErrTemporary
io.ErrShortBufferdispatch.ErrTemporary
io.ErrShortWritedispatch.ErrTemporary
io.ErrUnexpectedEOFdispatch.ErrTemporary