fixed format
This commit is contained in:
parent
cc5711bb5e
commit
89a2d697b3
1 changed files with 118 additions and 118 deletions
|
|
@ -1,153 +1,153 @@
|
|||
import {
|
||||
type UseQueryOptions,
|
||||
useQuery,
|
||||
useQueryClient,
|
||||
type UseQueryOptions,
|
||||
useQuery,
|
||||
useQueryClient,
|
||||
} from "@tanstack/react-query";
|
||||
import { useChat } from "@/contexts/chat-context";
|
||||
import { useGetSettingsQuery } from "./useGetSettingsQuery";
|
||||
|
||||
export interface ProviderHealthDetails {
|
||||
llm_model: string;
|
||||
embedding_model: string;
|
||||
endpoint?: string | null;
|
||||
llm_model: string;
|
||||
embedding_model: string;
|
||||
endpoint?: string | null;
|
||||
}
|
||||
|
||||
export interface ProviderHealthResponse {
|
||||
status: "healthy" | "unhealthy" | "error" | "backend-unavailable";
|
||||
message: string;
|
||||
provider?: string;
|
||||
llm_provider?: string;
|
||||
embedding_provider?: string;
|
||||
llm_error?: string | null;
|
||||
embedding_error?: string | null;
|
||||
details?: ProviderHealthDetails;
|
||||
status: "healthy" | "unhealthy" | "error" | "backend-unavailable";
|
||||
message: string;
|
||||
provider?: string;
|
||||
llm_provider?: string;
|
||||
embedding_provider?: string;
|
||||
llm_error?: string | null;
|
||||
embedding_error?: string | null;
|
||||
details?: ProviderHealthDetails;
|
||||
}
|
||||
|
||||
export interface ProviderHealthParams {
|
||||
provider?: "openai" | "ollama" | "watsonx";
|
||||
test_completion?: boolean;
|
||||
provider?: "openai" | "ollama" | "watsonx";
|
||||
test_completion?: boolean;
|
||||
}
|
||||
|
||||
// Track consecutive failures for exponential backoff
|
||||
const failureCountMap = new Map<string, number>();
|
||||
|
||||
export const useProviderHealthQuery = (
|
||||
params?: ProviderHealthParams,
|
||||
options?: Omit<
|
||||
UseQueryOptions<ProviderHealthResponse, Error>,
|
||||
"queryKey" | "queryFn"
|
||||
>,
|
||||
params?: ProviderHealthParams,
|
||||
options?: Omit<
|
||||
UseQueryOptions<ProviderHealthResponse, Error>,
|
||||
"queryKey" | "queryFn"
|
||||
>,
|
||||
) => {
|
||||
const queryClient = useQueryClient();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
// Get chat error state from context (ChatProvider wraps the entire app in layout.tsx)
|
||||
const { hasChatError, setChatError } = useChat();
|
||||
// Get chat error state from context (ChatProvider wraps the entire app in layout.tsx)
|
||||
const { hasChatError, setChatError } = useChat();
|
||||
|
||||
const { data: settings = {} } = useGetSettingsQuery();
|
||||
const { data: settings = {} } = useGetSettingsQuery();
|
||||
|
||||
async function checkProviderHealth(): Promise<ProviderHealthResponse> {
|
||||
try {
|
||||
const url = new URL("/api/provider/health", window.location.origin);
|
||||
async function checkProviderHealth(): Promise<ProviderHealthResponse> {
|
||||
try {
|
||||
const url = new URL("/api/provider/health", window.location.origin);
|
||||
|
||||
// Add provider query param if specified
|
||||
if (params?.provider) {
|
||||
url.searchParams.set("provider", params.provider);
|
||||
}
|
||||
// Add provider query param if specified
|
||||
if (params?.provider) {
|
||||
url.searchParams.set("provider", params.provider);
|
||||
}
|
||||
|
||||
// Add test_completion query param if specified or if chat error exists
|
||||
const testCompletion = params?.test_completion ?? hasChatError;
|
||||
if (testCompletion) {
|
||||
url.searchParams.set("test_completion", "true");
|
||||
}
|
||||
// Add test_completion query param if specified or if chat error exists
|
||||
const testCompletion = params?.test_completion ?? hasChatError;
|
||||
if (testCompletion) {
|
||||
url.searchParams.set("test_completion", "true");
|
||||
}
|
||||
|
||||
const response = await fetch(url.toString());
|
||||
const response = await fetch(url.toString());
|
||||
|
||||
if (response.ok) {
|
||||
return await response.json();
|
||||
} else if (response.status === 503) {
|
||||
// Backend is up but provider validation failed
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
return {
|
||||
status: "unhealthy",
|
||||
message: errorData.message || "Provider validation failed",
|
||||
provider: errorData.provider || params?.provider || "unknown",
|
||||
llm_provider: errorData.llm_provider,
|
||||
embedding_provider: errorData.embedding_provider,
|
||||
llm_error: errorData.llm_error,
|
||||
embedding_error: errorData.embedding_error,
|
||||
details: errorData.details,
|
||||
};
|
||||
} else {
|
||||
// Other backend errors (400, etc.) - treat as provider issues
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
return {
|
||||
status: "error",
|
||||
message: errorData.message || "Failed to check provider health",
|
||||
provider: errorData.provider || params?.provider || "unknown",
|
||||
llm_provider: errorData.llm_provider,
|
||||
embedding_provider: errorData.embedding_provider,
|
||||
llm_error: errorData.llm_error,
|
||||
embedding_error: errorData.embedding_error,
|
||||
details: errorData.details,
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
// Network error - backend is likely down, don't show provider banner
|
||||
return {
|
||||
status: "backend-unavailable",
|
||||
message: error instanceof Error ? error.message : "Connection failed",
|
||||
provider: params?.provider || "unknown",
|
||||
};
|
||||
}
|
||||
}
|
||||
if (response.ok) {
|
||||
return await response.json();
|
||||
} else if (response.status === 503) {
|
||||
// Backend is up but provider validation failed
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
return {
|
||||
status: "unhealthy",
|
||||
message: errorData.message || "Provider validation failed",
|
||||
provider: errorData.provider || params?.provider || "unknown",
|
||||
llm_provider: errorData.llm_provider,
|
||||
embedding_provider: errorData.embedding_provider,
|
||||
llm_error: errorData.llm_error,
|
||||
embedding_error: errorData.embedding_error,
|
||||
details: errorData.details,
|
||||
};
|
||||
} else {
|
||||
// Other backend errors (400, etc.) - treat as provider issues
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
return {
|
||||
status: "error",
|
||||
message: errorData.message || "Failed to check provider health",
|
||||
provider: errorData.provider || params?.provider || "unknown",
|
||||
llm_provider: errorData.llm_provider,
|
||||
embedding_provider: errorData.embedding_provider,
|
||||
llm_error: errorData.llm_error,
|
||||
embedding_error: errorData.embedding_error,
|
||||
details: errorData.details,
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
// Network error - backend is likely down, don't show provider banner
|
||||
return {
|
||||
status: "backend-unavailable",
|
||||
message: error instanceof Error ? error.message : "Connection failed",
|
||||
provider: params?.provider || "unknown",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const queryKey = ["provider", "health", params?.test_completion];
|
||||
const failureCountKey = queryKey.join("-");
|
||||
const queryKey = ["provider", "health", params?.test_completion];
|
||||
const failureCountKey = queryKey.join("-");
|
||||
|
||||
const queryResult = useQuery(
|
||||
{
|
||||
queryKey,
|
||||
queryFn: checkProviderHealth,
|
||||
retry: false, // Don't retry health checks automatically
|
||||
refetchInterval: (query) => {
|
||||
const data = query.state.data;
|
||||
const status = data?.status;
|
||||
const queryResult = useQuery(
|
||||
{
|
||||
queryKey,
|
||||
queryFn: checkProviderHealth,
|
||||
retry: false, // Don't retry health checks automatically
|
||||
refetchInterval: (query) => {
|
||||
const data = query.state.data;
|
||||
const status = data?.status;
|
||||
|
||||
// If healthy, reset failure count and check every 30 seconds
|
||||
// Also reset chat error flag if we're using test_completion=true and it succeeded
|
||||
if (status === "healthy") {
|
||||
failureCountMap.set(failureCountKey, 0);
|
||||
// If we were checking with test_completion=true due to chat errors, reset the flag
|
||||
if (hasChatError && setChatError) {
|
||||
setChatError(false);
|
||||
}
|
||||
return 30000;
|
||||
}
|
||||
// If healthy, reset failure count and check every 30 seconds
|
||||
// Also reset chat error flag if we're using test_completion=true and it succeeded
|
||||
if (status === "healthy") {
|
||||
failureCountMap.set(failureCountKey, 0);
|
||||
// If we were checking with test_completion=true due to chat errors, reset the flag
|
||||
if (hasChatError && setChatError) {
|
||||
setChatError(false);
|
||||
}
|
||||
return 30000;
|
||||
}
|
||||
|
||||
// If backend unavailable, use moderate polling
|
||||
if (status === "backend-unavailable") {
|
||||
return 15000;
|
||||
}
|
||||
// If backend unavailable, use moderate polling
|
||||
if (status === "backend-unavailable") {
|
||||
return 15000;
|
||||
}
|
||||
|
||||
// For unhealthy/error status, use exponential backoff
|
||||
const currentFailures = failureCountMap.get(failureCountKey) || 0;
|
||||
failureCountMap.set(failureCountKey, currentFailures + 1);
|
||||
// For unhealthy/error status, use exponential backoff
|
||||
const currentFailures = failureCountMap.get(failureCountKey) || 0;
|
||||
failureCountMap.set(failureCountKey, currentFailures + 1);
|
||||
|
||||
// Exponential backoff: 5s, 10s, 20s, then 30s
|
||||
const backoffDelays = [5000, 10000, 20000, 30000];
|
||||
const delay =
|
||||
backoffDelays[Math.min(currentFailures, backoffDelays.length - 1)];
|
||||
// Exponential backoff: 5s, 10s, 20s, then 30s
|
||||
const backoffDelays = [5000, 10000, 20000, 30000];
|
||||
const delay =
|
||||
backoffDelays[Math.min(currentFailures, backoffDelays.length - 1)];
|
||||
|
||||
return delay;
|
||||
},
|
||||
refetchOnWindowFocus: false, // Disabled to reduce unnecessary calls on tab switches
|
||||
refetchOnMount: true,
|
||||
staleTime: 30000, // Consider data stale after 30 seconds
|
||||
enabled: !!settings?.edited && options?.enabled !== false, // Only run after onboarding is complete
|
||||
...options,
|
||||
},
|
||||
queryClient,
|
||||
);
|
||||
return delay;
|
||||
},
|
||||
refetchOnWindowFocus: false, // Disabled to reduce unnecessary calls on tab switches
|
||||
refetchOnMount: true,
|
||||
staleTime: 30000, // Consider data stale after 30 seconds
|
||||
enabled: !!settings?.edited && options?.enabled !== false, // Only run after onboarding is complete
|
||||
...options,
|
||||
},
|
||||
queryClient,
|
||||
);
|
||||
|
||||
return queryResult;
|
||||
return queryResult;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue