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 errordispatch | 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.