Skip to content

Commit baf7403

Browse files
committed
add examples
1 parent 75b4fca commit baf7403

File tree

2 files changed

+180
-4
lines changed

2 files changed

+180
-4
lines changed

README.md

Lines changed: 178 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,187 @@ and Circuit Breaker on the same mechanism.
5353

5454
### Do HTTP request with retries
5555

56-
...
56+
```go
57+
interrupter := breaker.Multiplex(
58+
breaker.BreakBySignal(os.Interrupt, os.Interrupt, syscall.SIGINT, syscall.SIGTERM),
59+
breaker.BreakByTimeout(timeout),
60+
)
61+
defer interrupter.Close()
62+
63+
ctx := breaker.ToContext(interrupter)
64+
ctx = context.WithValue(ctx, header, "...")
65+
66+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, server.URL, nil)
67+
if err != nil {
68+
panic(err)
69+
}
70+
71+
var resp *http.Response
72+
action := func(ctx context.Context) (err error) {
73+
req = req.Clone(ctx)
74+
75+
source := ctx.Value(header).(string)
76+
req.Header.Set(header, source)
77+
78+
resp, err = http.DefaultClient.Do(req)
79+
return err
80+
}
81+
82+
if err := retry.Do(ctx, action); err != nil {
83+
panic(err)
84+
}
85+
```
86+
87+
<details>
88+
<summary>Full example</summary>
89+
90+
```go
91+
package main
92+
93+
import (
94+
"context"
95+
"fmt"
96+
"io"
97+
"net/http"
98+
"net/http/httptest"
99+
"os"
100+
"syscall"
101+
"time"
102+
103+
"github.com/kamilsk/breaker"
104+
"github.com/kamilsk/retry/v5"
105+
)
106+
107+
func main() {
108+
const (
109+
header = "X-Message"
110+
timeout = time.Minute
111+
)
112+
113+
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
114+
time.Sleep(timeout / 10)
115+
_, _ = rw.Write([]byte(req.Header.Get(header)))
116+
}))
117+
defer server.Close()
118+
119+
interrupter := breaker.Multiplex(
120+
breaker.BreakBySignal(os.Interrupt, os.Interrupt, syscall.SIGINT, syscall.SIGTERM),
121+
breaker.BreakByTimeout(timeout),
122+
)
123+
defer interrupter.Close()
124+
125+
ctx := breaker.ToContext(interrupter)
126+
ctx = context.WithValue(ctx, header, "flexible mechanism to make execution flow interruptible")
127+
128+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, server.URL, nil)
129+
if err != nil {
130+
panic(err)
131+
}
132+
133+
var resp *http.Response
134+
action := func(ctx context.Context) (err error) {
135+
req = req.Clone(ctx)
136+
137+
source := ctx.Value(header).(string)
138+
req.Header.Set(header, source)
139+
140+
resp, err = http.DefaultClient.Do(req)
141+
return err
142+
}
143+
144+
if err := retry.Do(ctx, action); err != nil {
145+
fmt.Println("error:", err)
146+
return
147+
}
148+
_, _ = io.Copy(os.Stdout, resp.Body)
149+
}
150+
```
151+
152+
[Play it](https://play.golang.org/p/IpMEC5GM0s9)!
153+
</details>
57154

58155
### Graceful Shutdown HTTP server
59156

60-
...
157+
```go
158+
interrupter := breaker.Multiplex(
159+
breaker.BreakBySignal(os.Interrupt, os.Interrupt, syscall.SIGINT, syscall.SIGTERM),
160+
breaker.BreakByTimeout(timeout),
161+
)
162+
defer interrupter.Close()
163+
164+
server := http.Server{
165+
BaseContext: func(net.Listener) context.Context {
166+
return breaker.ToContext(interrupter)
167+
},
168+
}
169+
go func() {
170+
if err := server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
171+
log.Fatal(err)
172+
}
173+
}()
174+
175+
<-interrupter.Done()
176+
if errors.Is(interrupter.Err(), breaker.Interrupted) {
177+
if err := server.Shutdown(context.TODO()); err != nil {
178+
panic(err)
179+
}
180+
}
181+
```
182+
183+
<details>
184+
<summary>Full example</summary>
185+
186+
```go
187+
package main
188+
189+
import (
190+
"context"
191+
"errors"
192+
"fmt"
193+
"log"
194+
"net"
195+
"net/http"
196+
"os"
197+
"syscall"
198+
"time"
199+
200+
"github.com/kamilsk/breaker"
201+
)
202+
203+
func main() {
204+
const timeout = time.Minute
205+
206+
interrupter := breaker.Multiplex(
207+
breaker.BreakBySignal(os.Interrupt, os.Interrupt, syscall.SIGINT, syscall.SIGTERM),
208+
breaker.BreakByTimeout(timeout),
209+
)
210+
defer interrupter.Close()
211+
212+
server := http.Server{
213+
Addr: ":8080",
214+
Handler: http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {}),
215+
BaseContext: func(net.Listener) context.Context {
216+
return breaker.ToContext(interrupter)
217+
},
218+
}
219+
go func() {
220+
if err := server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
221+
log.Fatal(err)
222+
}
223+
}()
224+
225+
<-interrupter.Done()
226+
if err := interrupter.Err(); errors.Is(err, breaker.Interrupted) {
227+
if err := server.Shutdown(context.TODO()); err != nil {
228+
panic(err)
229+
}
230+
}
231+
fmt.Println("graceful shutdown")
232+
}
233+
```
234+
235+
[Play it](https://play.golang.org/p/-5OyqynxWkr)!
236+
</details>
61237

62238
## 🧩 Integration
63239

breaker_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,11 +199,11 @@ func TestBreakBySignal(t *testing.T) {
199199
go func() {
200200
proc, err := os.FindProcess(os.Getpid())
201201
if err != nil {
202-
t.Fatal(err)
202+
t.Error(err)
203203
}
204204
err = proc.Signal(syscall.SIGCHLD)
205205
if err != nil {
206-
t.Fatal(err)
206+
t.Error(err)
207207
}
208208
}()
209209
select {

0 commit comments

Comments
 (0)