@@ -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
0 commit comments