refactor(timeout): reuse shared api request timeout

This commit is contained in:
2026-04-21 13:13:13 +00:00
parent 44eb9b9173
commit da7375c889
4 changed files with 27 additions and 7 deletions
+5 -1
View File
@@ -6,6 +6,7 @@ import * as http from 'node:http';
import type { IApiError, IChatCompletionRequest } from '../../interfaces/api.ts'; import type { IApiError, IChatCompletionRequest } from '../../interfaces/api.ts';
import { ClusterCoordinator } from '../../cluster/coordinator.ts'; import { ClusterCoordinator } from '../../cluster/coordinator.ts';
import { ContainerManager } from '../../containers/container-manager.ts'; import { ContainerManager } from '../../containers/container-manager.ts';
import { API_SERVER } from '../../constants.ts';
import { logger } from '../../logger.ts'; import { logger } from '../../logger.ts';
import { ModelRegistry } from '../../models/registry.ts'; import { ModelRegistry } from '../../models/registry.ts';
import { ModelLoader } from '../../models/loader.ts'; import { ModelLoader } from '../../models/loader.ts';
@@ -158,11 +159,14 @@ export class ChatHandler {
targetEndpoint: string, targetEndpoint: string,
body: IChatCompletionRequest, body: IChatCompletionRequest,
): Promise<void> { ): Promise<void> {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), API_SERVER.REQUEST_TIMEOUT_MS);
const response = await fetch(`${targetEndpoint}/v1/chat/completions`, { const response = await fetch(`${targetEndpoint}/v1/chat/completions`, {
method: 'POST', method: 'POST',
headers: this.buildForwardHeaders(req), headers: this.buildForwardHeaders(req),
body: JSON.stringify(body), body: JSON.stringify(body),
}); signal: controller.signal,
}).finally(() => clearTimeout(timeout));
if (body.stream) { if (body.stream) {
res.writeHead(response.status, { res.writeHead(response.status, {
+18 -3
View File
@@ -11,6 +11,7 @@ import type {
} from '../../interfaces/api.ts'; } from '../../interfaces/api.ts';
import { ClusterCoordinator } from '../../cluster/coordinator.ts'; import { ClusterCoordinator } from '../../cluster/coordinator.ts';
import { ContainerManager } from '../../containers/container-manager.ts'; import { ContainerManager } from '../../containers/container-manager.ts';
import { API_SERVER } from '../../constants.ts';
import { logger } from '../../logger.ts'; import { logger } from '../../logger.ts';
import { ModelRegistry } from '../../models/registry.ts'; import { ModelRegistry } from '../../models/registry.ts';
@@ -80,7 +81,7 @@ export class EmbeddingsHandler {
return; return;
} }
const response = await fetch(`${ensured.location.endpoint}/v1/embeddings`, { const response = await this.fetchWithTimeout(`${ensured.location.endpoint}/v1/embeddings`, {
method: 'POST', method: 'POST',
headers: this.buildForwardHeaders(req), headers: this.buildForwardHeaders(req),
body: JSON.stringify(requestBody), body: JSON.stringify(requestBody),
@@ -159,7 +160,7 @@ export class EmbeddingsHandler {
model: string, model: string,
input: string, input: string,
): Promise<{ vector: number[]; tokenCount: number }> { ): Promise<{ vector: number[]; tokenCount: number }> {
const response = await fetch(`${endpoint}/v1/embeddings`, { const response = await this.fetchWithTimeout(`${endpoint}/v1/embeddings`, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ model, input }), body: JSON.stringify({ model, input }),
@@ -181,7 +182,7 @@ export class EmbeddingsHandler {
_model: string, _model: string,
input: string, input: string,
): Promise<{ vector: number[]; tokenCount: number }> { ): Promise<{ vector: number[]; tokenCount: number }> {
const response = await fetch(`${endpoint}/embed`, { const response = await this.fetchWithTimeout(`${endpoint}/embed`, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ inputs: input }), body: JSON.stringify({ inputs: input }),
@@ -214,6 +215,20 @@ export class EmbeddingsHandler {
return headers; return headers;
} }
private async fetchWithTimeout(url: string, init: RequestInit): Promise<Response> {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), API_SERVER.REQUEST_TIMEOUT_MS);
try {
return await fetch(url, {
...init,
signal: controller.signal,
});
} finally {
clearTimeout(timeout);
}
}
private sendError( private sendError(
res: http.ServerResponse, res: http.ServerResponse,
statusCode: number, statusCode: number,
+2 -1
View File
@@ -11,6 +11,7 @@ import type {
TContainerType, TContainerType,
} from '../interfaces/container.ts'; } from '../interfaces/container.ts';
import type { IChatCompletionRequest, IChatCompletionResponse } from '../interfaces/api.ts'; import type { IChatCompletionRequest, IChatCompletionResponse } from '../interfaces/api.ts';
import { API_SERVER } from '../constants.ts';
import { ContainerRuntime } from '../docker/container-runtime.ts'; import { ContainerRuntime } from '../docker/container-runtime.ts';
import { logger } from '../logger.ts'; import { logger } from '../logger.ts';
@@ -165,7 +166,7 @@ export abstract class BaseContainer {
const url = `${endpoint}${path}`; const url = `${endpoint}${path}`;
const controller = new AbortController(); const controller = new AbortController();
const timeout = options.timeout || 30000; const timeout = options.timeout || API_SERVER.REQUEST_TIMEOUT_MS;
const timeoutId = setTimeout(() => controller.abort(), timeout); const timeoutId = setTimeout(() => controller.abort(), timeout);
try { try {
+2 -2
View File
@@ -4,7 +4,7 @@
import * as fs from 'node:fs/promises'; import * as fs from 'node:fs/promises';
import type { IModelCatalog, IModelCatalogEntry } from '../interfaces/catalog.ts'; import type { IModelCatalog, IModelCatalogEntry } from '../interfaces/catalog.ts';
import { MODEL_REGISTRY, TIMING } from '../constants.ts'; import { API_SERVER, MODEL_REGISTRY, TIMING } from '../constants.ts';
import { logger } from '../logger.ts'; import { logger } from '../logger.ts';
export class ModelRegistry { export class ModelRegistry {
@@ -167,7 +167,7 @@ export class ModelRegistry {
} }
const controller = new AbortController(); const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 30000); const timeout = setTimeout(() => controller.abort(), API_SERVER.REQUEST_TIMEOUT_MS);
try { try {
const response = await fetch(source, { const response = await fetch(source, {