fix(slurm): add default 30s timeout to HTTP client

Replaces http.DefaultClient with a client that has a 30s timeout to prevent indefinite hangs when the Slurm REST API is unresponsive.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
dailz
2026-04-10 09:25:35 +08:00
parent 1359730300
commit c070dd8abc
4 changed files with 13 additions and 8 deletions

View File

@@ -9,6 +9,7 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"strings" "strings"
"time"
) )
const ( const (
@@ -16,6 +17,8 @@ const (
DefaultBaseURL = "http://localhost:6820/" DefaultBaseURL = "http://localhost:6820/"
// DefaultUserAgent is the default User-Agent header value. // DefaultUserAgent is the default User-Agent header value.
DefaultUserAgent = "slurm-go-sdk" DefaultUserAgent = "slurm-go-sdk"
// DefaultTimeout is the default HTTP request timeout.
DefaultTimeout = 30 * time.Second
) )
// Client manages communication with the Slurm REST API. // Client manages communication with the Slurm REST API.
@@ -85,7 +88,7 @@ type Response struct {
// http.DefaultClient is used. // http.DefaultClient is used.
func NewClient(baseURL string, httpClient *http.Client) (*Client, error) { func NewClient(baseURL string, httpClient *http.Client) (*Client, error) {
if httpClient == nil { if httpClient == nil {
httpClient = http.DefaultClient httpClient = &http.Client{Timeout: DefaultTimeout}
} }
parsedURL, err := url.Parse(baseURL) parsedURL, err := url.Parse(baseURL)

View File

@@ -20,7 +20,7 @@ func TestNewClient(t *testing.T) {
t.Errorf("expected UserAgent %q, got %q", DefaultUserAgent, client.UserAgent) t.Errorf("expected UserAgent %q, got %q", DefaultUserAgent, client.UserAgent)
} }
if client.client == nil { if client.client == nil {
t.Error("expected http.Client to be initialized (nil httpClient should default to http.DefaultClient)") t.Error("expected http.Client to be initialized (nil httpClient should create a client with default timeout)")
} }
_, err = NewClient("://invalid", nil) _, err = NewClient("://invalid", nil)

View File

@@ -24,6 +24,8 @@ func defaultClientConfig() *clientConfig {
} }
} }
const defaultHTTPTimeout = 30 * time.Second
// WithJWTKey specifies the path to the JWT key file. // WithJWTKey specifies the path to the JWT key file.
func WithJWTKey(path string) ClientOption { func WithJWTKey(path string) ClientOption {
return func(c *clientConfig) error { return func(c *clientConfig) error {
@@ -89,11 +91,12 @@ func NewClientWithOpts(baseURL string, opts ...ClientOption) (*Client, error) {
} }
tr := NewJWTAuthTransport(cfg.username, key, transportOpts...) tr := NewJWTAuthTransport(cfg.username, key, transportOpts...)
httpClient = tr.Client() httpClient = &http.Client{
Transport: tr,
Timeout: defaultHTTPTimeout,
}
} else if cfg.httpClient != nil { } else if cfg.httpClient != nil {
httpClient = cfg.httpClient httpClient = cfg.httpClient
} else {
httpClient = http.DefaultClient
} }
return NewClient(baseURL, httpClient) return NewClient(baseURL, httpClient)

View File

@@ -2,7 +2,6 @@ package slurm
import ( import (
"crypto/rand" "crypto/rand"
"net/http"
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
@@ -61,8 +60,8 @@ func TestNewClientWithOpts_BackwardCompatible(t *testing.T) {
if client == nil { if client == nil {
t.Fatal("expected non-nil client") t.Fatal("expected non-nil client")
} }
if client.client != http.DefaultClient { if client.client.Timeout != DefaultTimeout {
t.Error("expected http.DefaultClient when no options provided") t.Errorf("expected Timeout=%v, got %v", DefaultTimeout, client.client.Timeout)
} }
} }