Skip to content
Dispatch Dispatch Dispatch
Go - Durable webhooks

Durable webhooks

A typical web application scenario is sending a notification request to a different server. Also known as a webhook, this technique often requires thinking through various failure modes and handling them.

What if the server is down? What if it’s slow? As developers, we usually start by implementing a retry mechanism. What if the server is overloaded? Let’s add exponential back-off. What if our program is a web server that needs to respond quickly? Let’s add a queue. The complexity of the code and infrastructure to handle these seemingly simple tasks grows quickly.

However, Dispatch can take care of all of that with a few lines of code.

Setup

If you haven’t already, make sure you have a Dispatch account and CLI installed.

Example code

Here’s the full code of the server that reliably sends webhooks:

package main
import (
"bytes"
"context"
"log"
"net/http"
"github.com/dispatchrun/dispatch-go"
)
type WebhookFailed struct{}
func (error *WebhookFailed) Error() string {
return "webhook endpoint has failed"
}
func (error *WebhookFailed) Temporary() bool {
return true
}
func main() {
send_webhook := dispatch.Func("send_webhook", func(ctx context.Context, url string) (any, error) {
response, err := http.Post(url, "text/plain", bytes.NewReader([]byte(`Hello webhook`)))
if err != nil {
return nil, &WebhookFailed{}
}
if response.StatusCode != 200 {
return nil, &WebhookFailed{}
}
return nil, nil
})
endpoint, err := dispatch.New(send_webhook)
if err != nil {
log.Fatal(err)
}
http.Handle(endpoint.Handler())
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
send_webhook.Dispatch(r.Context(), "https://httpstat.us/500")
w.WriteHeader(http.StatusOK)
})
if err := http.ListenAndServe("localhost:8000", nil); err != nil {
log.Fatal(err)
}
}

Save this code in a main.go file and run it with the Dispatch CLI:

dispatch run -- go run main.go

When a GET / request arrives, sendWebhook function is dispatched to send a webhook. Note that we are sending a webhook to a URL that will always return a 500. Since internal server errors are interpreted as temporary failures, Dispatch retries the operation.

dispatch | 2024-05-02 06:57:59.165 WARN function call failed function=sendWebhook status=Temporary error
dispatch | 2024-05-02 06:57:59.396 INFO calling function function=sendWebhook

This short program shows how easy it is to create reliable applications with just a few lines of code with Dispatch. We haven’t had to add extra infrastructure like queues, databases, or worker pools. Integration with Dispatch is entirely driven from the application code.