da440dil / go-re

Abstraction for retry strategies

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

go-re

GitHub Actions Coverage Status Go Reference Go Report Card

Re-execution for functions with configurable limits.

Example HTTP request

fn := func(ctx context.Context, url string) (string, error) {
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
	if err != nil {
		return "", err
	}
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return "", err
	}
	defer res.Body.Close()

	body, err := io.ReadAll(res.Body)
	if err != nil {
		return "", err
	}
	if res.StatusCode != http.StatusOK {
		err = fmt.Errorf("status code != %d, %w", http.StatusOK, re.ErrRetryable)
	}
	return fmt.Sprintf("{ statusCode: %d, body: %s }", res.StatusCode, body), err
}
// Use constant delay between retries 10 ms with maximum number of retries 1.
fn = re.Tryable(fn, re.Constant(time.Millisecond*10), re.MaxRetries(1))

x := 0
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	statusCode := http.StatusOK
	if x > 2 || x%2 != 0 { // { 0 => 200, 1 => 418, 2 => 200, ... => 418 }
		statusCode = http.StatusTeapot
	}
	w.WriteHeader(statusCode)
	fmt.Fprintf(w, "{ x: %d }", x)
	x++
}))
defer srv.Close()

for i := 0; i < 3; i++ {
	ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*100)
	defer cancel()

	v, err := fn(ctx, srv.URL)
	fmt.Printf("{ v: %v, err: %v }\n", v, err)
}
// Output:
// { v: { statusCode: 200, body: { x: 0 } }, err: <nil> }
// { v: { statusCode: 200, body: { x: 2 } }, err: <nil> }
// { v: { statusCode: 418, body: { x: 4 } }, err: status code != 200, retryable }

About

Abstraction for retry strategies

License:MIT License


Languages

Language:Go 100.0%