Skip to content

Commit

Permalink
net.http: add a retry mechanism to http.fetch(), when the socket inev…
Browse files Browse the repository at this point in the history
…itably errors (#19660)
  • Loading branch information
shove70 committed Oct 27, 2023
1 parent f74719d commit b3b68e4
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 7 deletions.
12 changes: 11 additions & 1 deletion vlib/net/http/backend_nix.c.v
Expand Up @@ -14,7 +14,17 @@ fn (req &Request) ssl_do(port int, method Method, host_name string, path string)
validate: req.validate
in_memory_verification: req.in_memory_verification
)!
ssl_conn.dial(host_name, port) or { return err }
mut retries := 0
for {
ssl_conn.dial(host_name, port) or {
retries++
if is_no_need_retry_error(err.code()) || retries >= req.max_retries {
return err
}
continue
}
break
}

req_headers := req.build_request_headers(method, host_name, path)
$if trace_http_request ? {
Expand Down
2 changes: 2 additions & 0 deletions vlib/net/http/http.v
Expand Up @@ -31,6 +31,7 @@ pub mut:
cert_key string // the path to a key.pem file, containing private keys for the client certificate(s)
in_memory_verification bool // if true, verify, cert, and cert_key are read from memory, not from a file
allow_redirect bool = true // whether to allow redirect
max_retries int = 5 // maximum number of retries required when an underlying socket error occurs
// callbacks to allow custom reporting code to run, while the request is running
on_redirect RequestRedirectFn = unsafe { nil }
on_progress RequestProgressFn = unsafe { nil }
Expand Down Expand Up @@ -164,6 +165,7 @@ pub fn fetch(config FetchConfig) !Response {
cert_key: config.cert_key
in_memory_verification: config.in_memory_verification
allow_redirect: config.allow_redirect
max_retries: config.max_retries
on_progress: config.on_progress
on_redirect: config.on_redirect
on_finish: config.on_finish
Expand Down
49 changes: 43 additions & 6 deletions vlib/net/http/request.v
Expand Up @@ -42,6 +42,7 @@ pub mut:
cert_key string
in_memory_verification bool // if true, verify, cert, and cert_key are read from memory, not from a file
allow_redirect bool = true // whether to allow redirect
max_retries int = 5 // maximum number of retries required when an underlying socket error occurs
// callbacks to allow custom reporting code to run, while the request is running
on_redirect RequestRedirectFn = unsafe { nil }
on_progress RequestProgressFn = unsafe { nil }
Expand Down Expand Up @@ -120,15 +121,42 @@ fn (req &Request) method_and_url_to_response(method Method, url urllib.URL) !Res
// println('fetch $method, $scheme, $host_name, $nport, $path ')
if scheme == 'https' && req.proxy == unsafe { nil } {
// println('ssl_do( $nport, $method, $host_name, $path )')
res := req.ssl_do(nport, method, host_name, path)!
return res
mut retries := 0
for {
res := req.ssl_do(nport, method, host_name, path) or {
retries++
if is_no_need_retry_error(err.code()) || retries >= req.max_retries {
return err
}
continue
}
return res
}
} else if scheme == 'http' && req.proxy == unsafe { nil } {
// println('http_do( $nport, $method, $host_name, $path )')
res := req.http_do('${host_name}:${nport}', method, path)!
return res
mut retries := 0
for {
res := req.http_do('${host_name}:${nport}', method, path) or {
retries++
if is_no_need_retry_error(err.code()) || retries >= req.max_retries {
return err
}
continue
}
return res
}
} else if req.proxy != unsafe { nil } {
res := req.proxy.http_do(host_name, method, path, req)!
return res
mut retries := 0
for {
res := req.proxy.http_do(host_name, method, path, req) or {
retries++
if is_no_need_retry_error(err.code()) || retries >= req.max_retries {
return err
}
continue
}
return res
}
}
return error('http.request.method_and_url_to_response: unsupported scheme: "${scheme}"')
}
Expand Down Expand Up @@ -470,3 +498,12 @@ fn parse_disposition(line string) map[string]string {
}
return data
}

fn is_no_need_retry_error(err_code int) bool {
return err_code in [
net.err_port_out_of_range.code(),
net.err_no_udp_remote.code(),
net.err_connect_timed_out.code(),
net.err_timed_out_code,
]
}

0 comments on commit b3b68e4

Please sign in to comment.