Skip to content

Commit 5faeaa9

Browse files
authored
Populate Request.values on creation (Azure#24817)
* Populate Request.values on creation This ensures that the same instance is propagated across policies and that any values are retained across retries. * improve test
1 parent 10288ad commit 5faeaa9

File tree

3 files changed

+54
-2
lines changed

3 files changed

+54
-2
lines changed

sdk/azcore/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
### Bugs Fixed
1010

11+
* Fixed incorrect request/response logging try info when logging a request that's being retried.
12+
1113
### Other Changes
1214

1315
## 1.18.0 (2025-04-03)

sdk/azcore/internal/exported/request.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ func (ov opValues) get(value any) bool {
7171
// NewRequestFromRequest creates a new policy.Request with an existing *http.Request
7272
// Exported as runtime.NewRequestFromRequest().
7373
func NewRequestFromRequest(req *http.Request) (*Request, error) {
74-
policyReq := &Request{req: req}
74+
// populate values so that the same instance is propagated across policies
75+
policyReq := &Request{req: req, values: opValues{}}
7576

7677
if req.Body != nil {
7778
// we can avoid a body copy here if the underlying stream is already a
@@ -117,7 +118,8 @@ func NewRequest(ctx context.Context, httpMethod string, endpoint string) (*Reque
117118
if !(req.URL.Scheme == "http" || req.URL.Scheme == "https") {
118119
return nil, fmt.Errorf("unsupported protocol scheme %s", req.URL.Scheme)
119120
}
120-
return &Request{req: req}, nil
121+
// populate values so that the same instance is propagated across policies
122+
return &Request{req: req, values: opValues{}}, nil
121123
}
122124

123125
// Body returns the original body specified when the Request was created.

sdk/azcore/runtime/policy_retry_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ import (
1010
"bytes"
1111
"context"
1212
"errors"
13+
"fmt"
1314
"io"
1415
"math"
1516
"net/http"
17+
"reflect"
1618
"strings"
1719
"testing"
1820
"time"
@@ -962,3 +964,49 @@ func TestCalcDelay(t *testing.T) {
962964
}
963965
})
964966
}
967+
968+
type retryLoggingChecker struct {
969+
count int32
970+
}
971+
972+
func (r *retryLoggingChecker) Do(req *policy.Request) (*http.Response, error) {
973+
if r.count > 0 {
974+
var opValues logPolicyOpValues
975+
req.OperationValue(&opValues)
976+
if reflect.ValueOf(opValues).IsZero() {
977+
// the logging policy is after us. so it should have populated logPolicyOpValues
978+
return nil, errors.New("unexpected zero-value for logPolicyOpValues")
979+
}
980+
981+
// verify that the logging policy is updating the try in opValues
982+
if r.count != opValues.try {
983+
return nil, fmt.Errorf("expected count %d, got %d", r.count, opValues.try)
984+
}
985+
}
986+
r.count++
987+
return req.Next()
988+
}
989+
990+
func TestRetryPolicyWithLoggingChecker(t *testing.T) {
991+
srv, close := mock.NewServer()
992+
defer close()
993+
srv.AppendResponse(mock.WithBodyReadError())
994+
srv.AppendResponse(mock.WithBodyReadError())
995+
srv.AppendResponse()
996+
pl := newTestPipeline(&policy.ClientOptions{
997+
Transport: srv, Retry: *testRetryOptions(),
998+
PerRetryPolicies: []policy.Policy{&retryLoggingChecker{}},
999+
})
1000+
req, err := NewRequest(context.Background(), http.MethodGet, srv.URL())
1001+
require.NoError(t, err)
1002+
1003+
body := newRewindTrackingBody("stuff")
1004+
require.NoError(t, req.SetBody(body, "text/plain"))
1005+
1006+
resp, err := pl.Do(req)
1007+
require.NoError(t, err)
1008+
require.EqualValues(t, http.StatusOK, resp.StatusCode)
1009+
require.EqualValues(t, 3, srv.Requests())
1010+
require.EqualValues(t, 2, body.rcount)
1011+
require.True(t, body.closed)
1012+
}

0 commit comments

Comments
 (0)