fix task duration recording
This commit is contained in:
parent
d09a4c2e4d
commit
ba419cd90a
@ -110,6 +110,7 @@ func TestOpenAIClientChatContract(t *testing.T) {
|
||||
t.Fatalf("decode request: %v", err)
|
||||
}
|
||||
gotModel, _ = body["model"].(string)
|
||||
time.Sleep(25 * time.Millisecond)
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
||||
"id": "chatcmpl-test",
|
||||
"object": "chat.completion",
|
||||
@ -145,6 +146,9 @@ func TestOpenAIClientChatContract(t *testing.T) {
|
||||
if response.RequestID != "req-chat-test" || response.ResponseStartedAt.IsZero() || response.ResponseFinishedAt.IsZero() {
|
||||
t.Fatalf("response metadata was not captured: %+v", response)
|
||||
}
|
||||
if response.ResponseDurationMS < 20 {
|
||||
t.Fatalf("response duration should include upstream latency, got %dms", response.ResponseDurationMS)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenAIClientChatStreamContract(t *testing.T) {
|
||||
|
||||
@ -27,11 +27,11 @@ func (c GeminiClient) Run(ctx context.Context, request Request) (Response, error
|
||||
return Response{}, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
responseStartedAt := time.Now()
|
||||
resp, err := httpClient(request.HTTPClient, c.HTTPClient).Do(req)
|
||||
if err != nil {
|
||||
return Response{}, &ClientError{Code: "network", Message: err.Error(), Retryable: true}
|
||||
}
|
||||
responseStartedAt := time.Now()
|
||||
requestID := requestIDFromHTTPResponse(resp)
|
||||
result, err := decodeHTTPResponse(resp)
|
||||
responseFinishedAt := time.Now()
|
||||
|
||||
@ -33,11 +33,11 @@ func (c OpenAIClient) Run(ctx context.Context, request Request) (Response, error
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Authorization", "Bearer "+apiKey)
|
||||
responseStartedAt := time.Now()
|
||||
resp, err := httpClient(request.HTTPClient, c.HTTPClient).Do(req)
|
||||
if err != nil {
|
||||
return Response{}, &ClientError{Code: "network", Message: err.Error(), Retryable: true}
|
||||
}
|
||||
responseStartedAt := time.Now()
|
||||
requestID := requestIDFromHTTPResponse(resp)
|
||||
result, err := decodeOpenAIResponse(resp, stream, request.StreamDelta)
|
||||
responseFinishedAt := time.Now()
|
||||
|
||||
@ -146,5 +146,8 @@ func responseDurationMS(startedAt time.Time, finishedAt time.Time) int64 {
|
||||
if duration < 0 {
|
||||
return 0
|
||||
}
|
||||
if duration == 0 && finishedAt.After(startedAt) {
|
||||
return 1
|
||||
}
|
||||
return duration
|
||||
}
|
||||
|
||||
@ -45,11 +45,11 @@ func (c VolcesClient) runImage(ctx context.Context, request Request, apiKey stri
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Authorization", "Bearer "+apiKey)
|
||||
|
||||
responseStartedAt := time.Now()
|
||||
resp, err := httpClient(request.HTTPClient, c.HTTPClient).Do(req)
|
||||
if err != nil {
|
||||
return Response{}, &ClientError{Code: "network", Message: err.Error(), Retryable: true}
|
||||
}
|
||||
responseStartedAt := time.Now()
|
||||
requestID := requestIDFromHTTPResponse(resp)
|
||||
result, err := decodeHTTPResponse(resp)
|
||||
responseFinishedAt := time.Now()
|
||||
|
||||
@ -812,7 +812,7 @@ function TaskRecord(props: { task: GatewayTask; token: string; onCopyRequestId:
|
||||
<TableCell>{props.task.apiKeyName || props.task.apiKeyPrefix || props.task.apiKeyId || '-'}</TableCell>
|
||||
<TableCell className="taskRecordTokenCell">{tokenUsage}</TableCell>
|
||||
<TableCell>{chargeText}</TableCell>
|
||||
<TableCell>{formatDuration(props.task.responseDurationMs)}</TableCell>
|
||||
<TableCell>{formatDuration(taskDurationMs(props.task))}</TableCell>
|
||||
<TableCell>{formatDateTime(props.task.createdAt)}</TableCell>
|
||||
<TableCell>
|
||||
<Button type="button" variant="ghost" size="sm" className="taskRecordJsonButton" title={taskErrorText(props.task) || '查看原始 JSON'} onClick={() => props.onOpenJson(props.task)}>
|
||||
@ -1029,7 +1029,7 @@ function taskAttemptMeta(attempt: NonNullable<GatewayTask['attempts']>[number])
|
||||
attempt.providerModelName || attempt.modelName || attempt.modelAlias,
|
||||
attempt.requestId ? `RequestID ${attempt.requestId}` : '',
|
||||
statusCode ? `状态码 ${statusCode}` : '',
|
||||
attempt.responseDurationMs ? formatDuration(attempt.responseDurationMs) : '',
|
||||
formatDuration(attemptDurationMs(attempt)),
|
||||
].filter(Boolean);
|
||||
return values.join(' · ') || attempt.clientId || '-';
|
||||
}
|
||||
@ -1355,10 +1355,41 @@ function tokenValue(value: unknown) {
|
||||
return Number.isFinite(numericValue) ? numericValue : null;
|
||||
}
|
||||
|
||||
function taskDurationMs(task: GatewayTask) {
|
||||
return (
|
||||
positiveDurationMs(task.responseDurationMs) ??
|
||||
elapsedDurationMs(task.responseStartedAt, task.responseFinishedAt) ??
|
||||
elapsedDurationMs(task.createdAt, task.finishedAt)
|
||||
);
|
||||
}
|
||||
|
||||
function attemptDurationMs(attempt: NonNullable<GatewayTask['attempts']>[number]) {
|
||||
return (
|
||||
positiveDurationMs(attempt.responseDurationMs) ??
|
||||
elapsedDurationMs(attempt.responseStartedAt, attempt.responseFinishedAt) ??
|
||||
elapsedDurationMs(attempt.startedAt, attempt.finishedAt)
|
||||
);
|
||||
}
|
||||
|
||||
function positiveDurationMs(value?: number) {
|
||||
if (value === undefined || value === null) return undefined;
|
||||
const numericValue = Number(value);
|
||||
return Number.isFinite(numericValue) && numericValue > 0 ? numericValue : undefined;
|
||||
}
|
||||
|
||||
function elapsedDurationMs(start?: string, end?: string) {
|
||||
if (!start || !end) return undefined;
|
||||
const startedAt = new Date(start).getTime();
|
||||
const finishedAt = new Date(end).getTime();
|
||||
if (!Number.isFinite(startedAt) || !Number.isFinite(finishedAt)) return undefined;
|
||||
const elapsed = finishedAt - startedAt;
|
||||
return elapsed > 0 ? Math.max(1, Math.round(elapsed)) : undefined;
|
||||
}
|
||||
|
||||
function formatDuration(value?: number) {
|
||||
if (value === undefined || value === null) return '-';
|
||||
const milliseconds = Math.max(0, Math.round(value));
|
||||
if (milliseconds === 0) return '0秒';
|
||||
if (milliseconds === 0) return '-';
|
||||
if (milliseconds < 1000) return `${milliseconds}毫秒`;
|
||||
const totalSeconds = Math.round(milliseconds / 1000);
|
||||
const hours = Math.floor(totalSeconds / 3600);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user