Changeset 0.28.8 (#194)
This commit is contained in:
@@ -2,6 +2,7 @@ package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
@@ -665,6 +666,10 @@ func (h *AdminHandler) FetchModels(c *gin.Context) {
|
||||
|
||||
added, updated, fetched, err := h.fetchModelsForProvider(c, cfg)
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrUpstreamTimeout) {
|
||||
c.JSON(http.StatusGatewayTimeout, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusBadGateway, gin.H{"error": "failed to fetch models: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
@@ -279,6 +280,10 @@ func (h *ProviderConfigHandler) FetchModels(c *gin.Context) {
|
||||
|
||||
result, err := syncAndEnableProviderModels(c.Request.Context(), h.stores, cfg, apiKey)
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrUpstreamTimeout) {
|
||||
c.JSON(http.StatusGatewayTimeout, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusBadGateway, gin.H{"error": "failed to fetch models: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -3,14 +3,35 @@ package handlers
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"git.gobha.me/xcaliber/chat-switchboard/models"
|
||||
"git.gobha.me/xcaliber/chat-switchboard/providers"
|
||||
"git.gobha.me/xcaliber/chat-switchboard/store"
|
||||
)
|
||||
|
||||
// providerSyncTimeout is the maximum time allowed for an outbound provider
|
||||
// HTTP call during model sync. Configurable via PROVIDER_SYNC_TIMEOUT env
|
||||
// var (seconds). Default 30s.
|
||||
var providerSyncTimeout = func() time.Duration {
|
||||
if v := os.Getenv("PROVIDER_SYNC_TIMEOUT"); v != "" {
|
||||
if n, err := strconv.Atoi(v); err == nil && n > 0 {
|
||||
return time.Duration(n) * time.Second
|
||||
}
|
||||
}
|
||||
return 30 * time.Second
|
||||
}()
|
||||
|
||||
// ErrUpstreamTimeout is returned when a provider API call exceeds the
|
||||
// configured timeout. Handlers use this to distinguish upstream timeouts
|
||||
// from other errors and return 504 instead of 502.
|
||||
var ErrUpstreamTimeout = errors.New("upstream timeout")
|
||||
|
||||
// syncResult holds the outcome of a model sync operation.
|
||||
type syncResult struct {
|
||||
Added int `json:"added"`
|
||||
@@ -62,8 +83,17 @@ func syncProviderModels(ctx context.Context, stores store.Stores, cfg *models.Pr
|
||||
}
|
||||
}
|
||||
|
||||
provModels, err := prov.ListModels(ctx, provCfg)
|
||||
// Wrap context with timeout for the outbound provider call.
|
||||
// All provider ListModels implementations use http.NewRequestWithContext,
|
||||
// so the deadline propagates to the HTTP transport automatically.
|
||||
syncCtx, cancel := context.WithTimeout(ctx, providerSyncTimeout)
|
||||
defer cancel()
|
||||
|
||||
provModels, err := prov.ListModels(syncCtx, provCfg)
|
||||
if err != nil {
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
return syncResult{}, fmt.Errorf("%w: %s", ErrUpstreamTimeout, cfg.Provider)
|
||||
}
|
||||
return syncResult{}, err
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user