(ctx context.Context, compr Compression, msgType WriteMessageType, payload []byte, attempt int)
| 296 | } |
| 297 | |
| 298 | func (r *API) attemptWrite(ctx context.Context, compr Compression, msgType WriteMessageType, payload []byte, attempt int) (WriteResponseStats, error) { |
| 299 | req, err := http.NewRequest(http.MethodPost, r.baseURL.String(), bytes.NewReader(payload)) |
| 300 | if err != nil { |
| 301 | // Errors from NewRequest are from unparsable URLs, so are not |
| 302 | // recoverable. |
| 303 | return WriteResponseStats{}, err |
| 304 | } |
| 305 | |
| 306 | req.Header.Add("Content-Encoding", string(compr)) |
| 307 | req.Header.Set("Content-Type", contentTypeHeader(msgType)) |
| 308 | if msgType == WriteV1MessageType { |
| 309 | // Compatibility mode for 1.0. |
| 310 | req.Header.Set(versionHeader, version1HeaderValue) |
| 311 | } else { |
| 312 | req.Header.Set(versionHeader, version20HeaderValue) |
| 313 | } |
| 314 | |
| 315 | if attempt > 0 { |
| 316 | req.Header.Set("Retry-Attempt", strconv.Itoa(attempt)) |
| 317 | } |
| 318 | |
| 319 | resp, err := r.opts.client.Do(req.WithContext(ctx)) |
| 320 | if err != nil { |
| 321 | // Errors from Client.Do are likely network errors, so recoverable. |
| 322 | return WriteResponseStats{}, retryableError{err, 0} |
| 323 | } |
| 324 | defer resp.Body.Close() |
| 325 | |
| 326 | body, err := io.ReadAll(resp.Body) |
| 327 | if err != nil { |
| 328 | return WriteResponseStats{}, fmt.Errorf("reading response body: %w", err) |
| 329 | } |
| 330 | |
| 331 | rs := WriteResponseStats{} |
| 332 | if msgType == WriteV2MessageType { |
| 333 | rs, err = parseWriteResponseStats(resp) |
| 334 | if err != nil { |
| 335 | r.opts.logger.Warn("parsing rw write statistics failed; partial or no stats", "err", err) |
| 336 | } |
| 337 | } |
| 338 | |
| 339 | if resp.StatusCode/100 == 2 { |
| 340 | return rs, nil |
| 341 | } |
| 342 | |
| 343 | err = fmt.Errorf("server returned HTTP status %s: %s", resp.Status, body) |
| 344 | if resp.StatusCode/100 == 5 || |
| 345 | (r.opts.retryOnRateLimit && resp.StatusCode == http.StatusTooManyRequests) { |
| 346 | return rs, retryableError{err, retryAfterDuration(resp.Header.Get("Retry-After"))} |
| 347 | } |
| 348 | return rs, err |
| 349 | } |
| 350 | |
| 351 | // retryAfterDuration returns the duration for the Retry-After header. In case of any errors, it |
| 352 | // returns 0 as if the header was never supplied. |
no test coverage detected