Skip to content

Go SDK: Hard-coded 5s timeout for WS token fetch causes spurious context deadline exceeded and ignores transport/options #69

@Shaahkral

Description

@Shaahkral

SDK/Area

  • sdk/golang
  • WebSocket bootstrap / token provider
  • File: sdk/golang/internal/infra/default_ws_token_provider.go

Summary

The Go SDK hard-codes a 5-second context deadline when fetching the WebSocket bullet token. On slower/variable networks (VPN, IPv6 fallback/Happy-Eyeballs, MTU quirks, congested edges), the POST to /api/v1/bullet-public sometimes exceeds 5s, leading to repeated context deadline exceeded failures—even though the endpoint is healthy and reachable and even when the app/transport is configured with a higher timeout.

This timeout also does not honor the SDK’s configured HTTP transport timeout or any WebSocket client option, so users cannot adjust it without vendoring/patching.

// sdk/golang/internal/infra/default_ws_token_provider.go
func (p *DefaultWsTokenProvider) GetToken() (error, []*interfaces.WsToken) {
    ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) // ← hard-coded 5s
    defer cancel()

    path := PathPublic
    if p.private {
        path = PathPrivate
    }

    resp := &tokenResponse{}
    err := p.transport.Call(ctx, p.domain, false, "Post", path, nil, resp, false)
    if err != nil {
        return err, nil
    }
    for _, sr := range resp.Servers {
        sr.Token = resp.Token
    }
    return nil, resp.Servers
}

Actual behavior

With certain networks, the WS bootstrap fails:
Post "https://api.kucoin.com/api/v1/bullet-public": context deadline exceeded
The failure repeats per attempt, regardless of increasing retry count/delay via SDK options, because each attempt still uses a 5s context deadline internally.

Expected behavior

The token request should respect a configurable timeout (e.g., from transport or WS client options), or at least use a more generous default (e.g., 20–30s) suitable for real-world networks.
Ideally, the timeout should inherit from the configured HTTP client/transport rather than being hard-coded locally.

Why this is a problem (real-world repro)

From the same host over VPN, a direct curl to https://api.kucoin.com/api/v1/bullet-public succeeds (HTTP/2 200) while the SDK call times out after ~5s. This indicates a deadline issue in the SDK rather than endpoint health.

Environments with IPv6 first / fallback to IPv4 often incur extra connection setup time; a 5s cap is too tight for initial TLS + HTTP/2 handshakes via some VPN providers or Cloudflare edges.

Proposed fixes (compatible options)

A. Honor configured timeouts (preferred):

Plumb a timeout from WebSocketClientOption (e.g., TokenRequestTimeout time.Duration).
If unset, default to the HTTP transport’s timeout (if available) or to a more forgiving default (e.g., 30s).

B. Remove the hard-coded deadline here and rely on the HTTP client timeout:

Use ctx := context.Background() (or a caller-provided ctx) and let p.transport enforce timeouts.

C. At minimum, increase the default:

Change time.Second5 → time.Second30. (Still sub-optimal because it’s not user-configurable.)

Backward compatibility

Introducing TokenRequestTimeout is backward-compatible; existing users keep the new default if they don’t set it.
Relying on transport timeout aligns with user expectations (many already tune HTTP timeouts globally).

Thank you

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions