Add server-side timeout handling to Ollama Cloud streaming
- Added 60 second timeout per chunk in parseStreamingResponse - Added 120 second timeout to makeRequest with AbortController - This prevents the server from hanging indefinitely on slow/unresponsive API This should fix the UI freeze when sending messages to Ollama Cloud models.
This commit is contained in:
@@ -338,12 +338,39 @@ export class OllamaCloudClient {
|
||||
|
||||
const reader = response.body.getReader()
|
||||
const decoder = new TextDecoder()
|
||||
const STREAM_TIMEOUT_MS = 60000 // 60 second timeout per chunk
|
||||
let lastActivity = Date.now()
|
||||
|
||||
const checkTimeout = () => {
|
||||
if (Date.now() - lastActivity > STREAM_TIMEOUT_MS) {
|
||||
reader.cancel().catch(() => { })
|
||||
throw new Error("Stream timeout - no data received for 60 seconds")
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
const { done, value } = await reader.read()
|
||||
checkTimeout()
|
||||
|
||||
// Create a timeout promise
|
||||
const timeoutPromise = new Promise<never>((_, reject) => {
|
||||
setTimeout(() => reject(new Error("Read timeout")), STREAM_TIMEOUT_MS)
|
||||
})
|
||||
|
||||
// Race the read against the timeout
|
||||
let result: ReadableStreamReadResult<Uint8Array>
|
||||
try {
|
||||
result = await Promise.race([reader.read(), timeoutPromise])
|
||||
} catch (timeoutError) {
|
||||
reader.cancel().catch(() => { })
|
||||
throw new Error("Stream read timeout")
|
||||
}
|
||||
|
||||
const { done, value } = result
|
||||
if (done) break
|
||||
|
||||
lastActivity = Date.now()
|
||||
|
||||
const lines = decoder.decode(value, { stream: true }).split('\n').filter(line => line.trim())
|
||||
|
||||
for (const line of lines) {
|
||||
@@ -371,7 +398,7 @@ export class OllamaCloudClient {
|
||||
}
|
||||
}
|
||||
|
||||
private async makeRequest(endpoint: string, options: RequestInit): Promise<Response> {
|
||||
private async makeRequest(endpoint: string, options: RequestInit, timeoutMs: number = 120000): Promise<Response> {
|
||||
// Ensure endpoint starts with /api
|
||||
const apiEndpoint = endpoint.startsWith('/api') ? endpoint : `/api${endpoint}`
|
||||
const url = `${this.baseUrl}${apiEndpoint}`
|
||||
@@ -386,10 +413,19 @@ export class OllamaCloudClient {
|
||||
|
||||
console.log(`[OllamaCloud] Making request to: ${url}`)
|
||||
|
||||
return fetch(url, {
|
||||
...options,
|
||||
headers
|
||||
})
|
||||
// Add timeout to prevent indefinite hangs
|
||||
const controller = new AbortController()
|
||||
const timeoutId = setTimeout(() => controller.abort(), timeoutMs)
|
||||
|
||||
try {
|
||||
return await fetch(url, {
|
||||
...options,
|
||||
headers,
|
||||
signal: controller.signal
|
||||
})
|
||||
} finally {
|
||||
clearTimeout(timeoutId)
|
||||
}
|
||||
}
|
||||
|
||||
async getCloudModels(): Promise<OllamaModel[]> {
|
||||
|
||||
Reference in New Issue
Block a user