Skip to content

Commit

Permalink
remote ais (backend): differentiate configured timeouts
Browse files Browse the repository at this point in the history
* config.client: allow zero (ie., unlimited) timeout
* config.client: unify valid ranges, constants
* remais: additional client with long timeout (to GET,PUT,LIST)
* is-client-timeout helper

Signed-off-by: Alex Aizman <[email protected]>
  • Loading branch information
alex-aizman committed Dec 10, 2024
1 parent 01561b7 commit 2ac6b70
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 14 deletions.
28 changes: 23 additions & 5 deletions ais/backend/ais.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 45,7 @@ type (
url string
uuid string
bp api.BaseParams
bpL api.BaseParams // long & list
}
AISbp struct {
t core.TargetPut
Expand Down Expand Up @@ -94,6 95,9 @@ func extractErrCode(e error, uuid string) (int, error) {
if e == nil {
return http.StatusOK, nil
}
if cos.IsClientTimeout(e) {
return http.StatusRequestTimeout, e
}
herr := cmn.Err2HTTPErr(e)
if herr == nil {
return http.StatusInternalServerError, e
Expand Down Expand Up @@ -257,7 261,9 @@ func (r *remAis) init(alias string, confURLs []string, cfg *cmn.ClusterConfig) (
var (
url string
remSmap, smap *meta.Smap
cliH, cliTLS = remaisClients(&cfg.Client)

clientL http.Client
cliH, cliTLS = remaisClients(&cfg.Client)
)
for _, u := range confURLs {
client := cliH
Expand Down Expand Up @@ -289,10 295,17 @@ func (r *remAis) init(alias string, confURLs []string, cfg *cmn.ClusterConfig) (
r.smap, r.url = remSmap, url
if cos.IsHTTPS(url) {
r.bp = api.BaseParams{Client: cliTLS, URL: url, UA: ua}
clientL = *cliTLS
} else {
r.bp = api.BaseParams{Client: cliH, URL: url, UA: ua}
clientL = *cliH
}

r.bpL = r.bp
clientL.Timeout = cfg.Client.TimeoutLong.D()
r.bpL.Client = &clientL
r.uuid = remSmap.UUID

return
}

Expand Down Expand Up @@ -446,7 459,7 @@ func (m *AISbp) ListObjects(remoteBck *meta.Bck, msg *apc.LsoMsg, lst *cmn.LsoRe
unsetUUID(&bck)

var lstRes *cmn.LsoRes
if lstRes, err = api.ListObjectsPage(remAis.bp, bck, remoteMsg, api.ListArgs{}); err != nil {
if lstRes, err = api.ListObjectsPage(remAis.bpL, bck, remoteMsg, api.ListArgs{}); err != nil {
ecode, err = extractErrCode(err, remAis.uuid)
return
}
Expand Down Expand Up @@ -540,6 553,7 @@ func (m *AISbp) HeadObj(_ context.Context, lom *core.LOM, _ *http.Request) (oa *
return
}

// TODO: retry
func (m *AISbp) GetObj(_ context.Context, lom *core.LOM, owt cmn.OWT, _ *http.Request) (ecode int, err error) {
var (
remAis *remAis
Expand All @@ -551,7 565,7 @@ func (m *AISbp) GetObj(_ context.Context, lom *core.LOM, owt cmn.OWT, _ *http.Re
return
}
unsetUUID(&remoteBck)
if r, size, err = api.GetObjectReader(remAis.bp, remoteBck, lom.ObjName, nil /*api.GetArgs*/); err != nil {
if r, size, err = api.GetObjectReader(remAis.bpL, remoteBck, lom.ObjName, nil /*api.GetArgs*/); err != nil {
return extractErrCode(err, remAis.uuid)
}
params := core.AllocPutParams()
Expand All @@ -564,6 578,9 @@ func (m *AISbp) GetObj(_ context.Context, lom *core.LOM, owt cmn.OWT, _ *http.Re
}
err = m.t.PutObject(lom, params)
core.FreePutParams(params)

// TODO: retry upon 'unreachable' or timeout

return extractErrCode(err, remAis.uuid)
}

Expand Down Expand Up @@ -599,11 616,12 @@ func (m *AISbp) GetObjReader(_ context.Context, lom *core.LOM, offset, length in
res.ExpCksum = oa.Cksum
lom.SetCksum(nil)
}
res.R, res.Size, res.Err = api.GetObjectReader(remAis.bp, remoteBck, lom.ObjName, args)
res.R, res.Size, res.Err = api.GetObjectReader(remAis.bpL, remoteBck, lom.ObjName, args)
res.ErrCode, res.Err = extractErrCode(res.Err, remAis.uuid)
return
}

// TODO: retry upon 'unreachable' or timeout
func (m *AISbp) PutObj(r io.ReadCloser, lom *core.LOM, _ *http.Request) (ecode int, err error) {
var (
oah api.ObjAttrs
Expand All @@ -617,7 635,7 @@ func (m *AISbp) PutObj(r io.ReadCloser, lom *core.LOM, _ *http.Request) (ecode i
unsetUUID(&remoteBck)
size := lom.Lsize(true) // _special_ as it's still a workfile at this point
args := api.PutArgs{
BaseParams: remAis.bp,
BaseParams: remAis.bpL,
Bck: remoteBck,
ObjName: lom.ObjName,
Cksum: lom.Checksum(),
Expand Down
4 changes: 1 addition & 3 deletions api/ls.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 5,6 @@
package api

import (
"context"
"errors"
"net/http"
"net/url"
"strconv"
Expand Down Expand Up @@ -204,7 202,7 @@ func lsoPage(reqParams *ReqParams) (_ *cmn.LsoRes, err error) {
if _, err = reqParams.DoReqAny(page); err == nil {
return page, nil
}
if !errors.Is(err, context.DeadlineExceeded) {
if !cos.IsClientTimeout(err) {
break
}
client := *reqParams.BaseParams.Client
Expand Down
22 changes: 16 additions & 6 deletions cmn/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -880,15 880,25 @@ func (c *LogConf) Validate() error {
// ClientConf //
////////////////

const (
minClientTimeout = time.Second
maxClientTimeout = 30 * time.Minute

errExpectedRange = "(expected range [1s, 30m] or zero)"
)

func (c *ClientConf) Validate() error {
if j := c.Timeout.D(); j < time.Second || j > 2*time.Minute {
return fmt.Errorf("invalid client.client_timeout=%s (expected range [1s, 2m])", j)
if j := c.Timeout.D(); j != 0 && (j < minClientTimeout || j > maxClientTimeout) {
return fmt.Errorf("invalid client_timeout=%s %s", j, errExpectedRange)
}
if j := c.TimeoutLong.D(); j != 0 && (j < minClientTimeout || j > maxClientTimeout) {
return fmt.Errorf("invalid client_long_timeout=%s %s", j, errExpectedRange)
}
if j := c.TimeoutLong.D(); j < 30*time.Second || j < c.Timeout.D() || j > 30*time.Minute {
return fmt.Errorf("invalid client.client_long_timeout=%s (expected range [30s, 30m])", j)
if j := c.TimeoutLong.D(); j != 0 && j < c.Timeout.D() {
return fmt.Errorf("client_long_timeout=%s cannot be less than client_timeout=%s", j, c.Timeout.D())
}
if j := c.ListObjTimeout.D(); j < 2*time.Second || j > 15*time.Minute {
return fmt.Errorf("invalid client.list_timeout=%s (expected range [2s, 15m])", j)
if j := c.ListObjTimeout.D(); j != 0 && (j < minClientTimeout || j > maxClientTimeout) {
return fmt.Errorf("invalid list_timeout=%s %s", j, errExpectedRange)
}
return nil
}
Expand Down
4 changes: 4 additions & 0 deletions cmn/cos/err.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 188,10 @@ func IsErrDNSLookup(err error) bool {
return errors.As(err, &wrapped)
}

func IsClientTimeout(err error) bool {
return errors.Is(err, context.DeadlineExceeded)
}

func IsUnreachable(err error, status int) bool {
return IsErrConnectionRefused(err) ||
IsErrDNSLookup(err) ||
Expand Down

0 comments on commit 2ac6b70

Please sign in to comment.