Skip to content

Commit 712ef08

Browse files
committed
Add per request timeout
1 parent 3e2f372 commit 712ef08

File tree

4 files changed

+50
-1
lines changed

4 files changed

+50
-1
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.1.15 (unreleased)
2+
3+
- Add configurable per request HTTP timeout
4+
15
## 0.1.14
26

37
- Extend default wait time for release of device database lock to 120 seconds and make it configurable

client.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,11 +310,21 @@ func (client *Client) Do(req Req) (Res, error) {
310310
defer client.mutex.Unlock()
311311
}
312312

313+
// Use per-request timeout if specified, otherwise use client's default timeout
314+
httpClient := client.HttpClient
315+
if req.Timeout > 0 {
316+
httpClient = &http.Client{
317+
Timeout: req.Timeout,
318+
Transport: client.HttpClient.Transport,
319+
Jar: client.HttpClient.Jar,
320+
}
321+
}
322+
313323
for attempts := 0; ; attempts++ {
314324
req.HttpReq.Body = io.NopCloser(bytes.NewBuffer(body))
315325
log.Printf("[DEBUG] HTTP Request: %s, %s, %s", req.HttpReq.Method, req.HttpReq.URL, req.HttpReq.Body)
316326

317-
httpRes, err := client.HttpClient.Do(req.HttpReq)
327+
httpRes, err := httpClient.Do(req.HttpReq)
318328
if err != nil {
319329
if ok := client.Backoff(attempts); !ok {
320330
log.Printf("[ERROR] HTTP Connection error occured: %+v", err)

client_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,28 @@ func TestNewClient(t *testing.T) {
3838
assert.Equal(t, client.MaxRetries, 0)
3939
}
4040

41+
// TestPerRequestTimeout tests per-request timeout functionality.
42+
func TestPerRequestTimeout(t *testing.T) {
43+
defer gock.Off()
44+
client := testClient()
45+
46+
// Test that the timeout modifier function works correctly
47+
req := client.NewReq("GET", RestconfDataEndpoint+"/url", nil, Timeout(30*time.Second))
48+
assert.Equal(t, req.Timeout, 30*time.Second)
49+
50+
// Test that the timeout modifier function works on existing requests
51+
timeoutFunc := Timeout(45 * time.Second)
52+
req2 := client.NewReq("GET", RestconfDataEndpoint+"/url", nil)
53+
timeoutFunc(&req2)
54+
assert.Equal(t, req2.Timeout, 45*time.Second)
55+
56+
// Test convenience methods with timeout modifier
57+
// This mainly tests that the modifier is properly passed through
58+
gock.New(testURL).Get("/restconf/data/test").Reply(200)
59+
_, err := client.GetData("test", Timeout(15*time.Second))
60+
assert.NoError(t, err)
61+
}
62+
4163
// TestDiscoverRestconfEndpoint tests the Client::discoverRestconfEndpoint method.
4264
func TestDiscoverRestconfEndpoint(t *testing.T) {
4365
defer gock.Off()

req.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package restconf
33
import (
44
"encoding/json"
55
"net/http"
6+
"time"
67

78
"github.com/tidwall/gjson"
89
"github.com/tidwall/sjson"
@@ -63,6 +64,8 @@ type Req struct {
6364
HttpReq *http.Request
6465
// Wait until write operation is complete.
6566
Wait bool
67+
// Timeout for this specific request (optional).
68+
Timeout time.Duration
6669
}
6770

6871
// Query sets an HTTP query parameter.
@@ -87,3 +90,13 @@ func Query(k, v string) func(req *Req) {
8790
func Wait(req *Req) {
8891
req.Wait = true
8992
}
93+
94+
// Timeout sets a custom timeout for this specific request.
95+
// If not set, the client's default timeout will be used.
96+
//
97+
// client.GetData("Cisco-IOS-XE-native:native", restconf.Timeout(30*time.Second))
98+
func Timeout(timeout time.Duration) func(req *Req) {
99+
return func(req *Req) {
100+
req.Timeout = timeout
101+
}
102+
}

0 commit comments

Comments
 (0)