fix:修复队列没有日志
This commit is contained in:
1 parent
dc74a5087a
commit
8ddc64becb
4 files changed
+26
-63
No files matched your search
@@ -2,6 +2,19 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### ????
|
||||
|
||||
- **[proxy/usage]**: ???? usage ?????? ? by lsy
|
||||
- ??: ??????????
|
||||
- ??: apps/worker/src/routes/proxy.ts:70-560, .helloagents/modules/proxy.md:20-40, .helloagents/modules/usage.md:10-30
|
||||
|
||||
|
||||
### ??
|
||||
|
||||
- **[proxy/usage]**: ?? usage ???????????? ? by lsy
|
||||
- ??: [202603181533_usage-event-call-fix](archive/2026-03/202603181533_usage-event-call-fix/)
|
||||
|
||||
|
||||
### 新增
|
||||
|
||||
- **[deploy-workflow]**: 新增本地一键部署脚本(init/update) — by lsy
|
||||
@@ -227,6 +240,9 @@
|
||||
|
||||
### 快速修改
|
||||
|
||||
- **[deploy-workflow]**: 本地部署脚本移除 .env 自动生成与加载 — by lsy
|
||||
- 类型: 快速修改(无方案包)
|
||||
- 文件: scripts/deploy.mjs:1-292
|
||||
- **[admin-ui/settings]**: 缓存 TTL 与版本成对展示为卡片 — by lsy
|
||||
- 类型: 快速修改(无方案包)
|
||||
- 文件: apps/ui/src/features/SettingsView.tsx:417-632
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
- 对 `/v1/responses` 且上游返回 400/404 时回退为 `/responses` 重试一次
|
||||
- 可配置失败重试轮询(响应 5xx/429 时触发)
|
||||
- 记录流式请求标记、首 token 延迟与推理强度到 usage_logs
|
||||
- usage 事件调度仅传 event 对象,失败请求也必须记录 error usage
|
||||
- 使用日志与模型能力写入可通过 `USAGE_QUEUE` 异步化(队列不可用时自动回退同步写入)
|
||||
- 队列写入采用“两态简化逻辑”:未超限时按比例直写/队列,超限后全部直写
|
||||
- 队列日限额由 `UsageLimiter` DO 维护,限制 `USAGE_QUEUE` 的日内发送量
|
||||
|
||||
@@ -531,7 +531,7 @@ proxy.all("/*", tokenAuth, async (c) => {
|
||||
}) => {
|
||||
const latencyMs = Date.now() - requestStart;
|
||||
const errorMessage = options.message ?? options.code;
|
||||
scheduleUsageEvent(c, {
|
||||
scheduleUsageEvent({
|
||||
type: "usage",
|
||||
payload: {
|
||||
tokenId: tokenRecord.id,
|
||||
@@ -938,7 +938,7 @@ proxy.all("/*", tokenAuth, async (c) => {
|
||||
selectedUpstreamModel = upstreamModel;
|
||||
lastErrorDetails = null;
|
||||
if (recordModel) {
|
||||
scheduleUsageEvent(c, {
|
||||
scheduleUsageEvent({
|
||||
type: "capability_upsert",
|
||||
payload: {
|
||||
channelId: channel.id,
|
||||
@@ -960,7 +960,7 @@ proxy.all("/*", tokenAuth, async (c) => {
|
||||
errorInfo.errorCode,
|
||||
);
|
||||
if (recordModel && cooldownSeconds > 0 && cooldownEligible) {
|
||||
scheduleUsageEvent(c, {
|
||||
scheduleUsageEvent({
|
||||
type: "model_error",
|
||||
payload: {
|
||||
channelId: channel.id,
|
||||
@@ -976,7 +976,7 @@ proxy.all("/*", tokenAuth, async (c) => {
|
||||
cooldownSeconds > 0 &&
|
||||
cooldownEligible
|
||||
) {
|
||||
scheduleUsageEvent(c, {
|
||||
scheduleUsageEvent({
|
||||
type: "model_error",
|
||||
payload: {
|
||||
channelId: channel.id,
|
||||
@@ -1012,7 +1012,7 @@ proxy.all("/*", tokenAuth, async (c) => {
|
||||
isTimeout ? "timeout" : "exception",
|
||||
);
|
||||
if (recordModel && cooldownSeconds > 0 && cooldownEligible) {
|
||||
scheduleUsageEvent(c, {
|
||||
scheduleUsageEvent({
|
||||
type: "model_error",
|
||||
payload: {
|
||||
channelId: channel.id,
|
||||
@@ -1028,7 +1028,7 @@ proxy.all("/*", tokenAuth, async (c) => {
|
||||
cooldownSeconds > 0 &&
|
||||
cooldownEligible
|
||||
) {
|
||||
scheduleUsageEvent(c, {
|
||||
scheduleUsageEvent({
|
||||
type: "model_error",
|
||||
payload: {
|
||||
channelId: channel.id,
|
||||
@@ -1060,7 +1060,7 @@ proxy.all("/*", tokenAuth, async (c) => {
|
||||
latency_ms: latencyMs,
|
||||
last_channel_id: lastChannel?.id ?? null,
|
||||
});
|
||||
scheduleUsageEvent(c, {
|
||||
scheduleUsageEvent({
|
||||
type: "usage",
|
||||
payload: {
|
||||
tokenId: tokenRecord.id,
|
||||
@@ -1113,7 +1113,7 @@ proxy.all("/*", tokenAuth, async (c) => {
|
||||
? usageMissingReason ?? "usage_missing"
|
||||
: null
|
||||
: errorDetails?.errorMessage ?? null;
|
||||
scheduleUsageEvent(c, {
|
||||
scheduleUsageEvent({
|
||||
type: "usage",
|
||||
payload: {
|
||||
tokenId: tokenRecord.id,
|
||||
|
||||
+1
-55
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
import { spawn } from "node:child_process";
|
||||
import { access, readFile, writeFile } from "node:fs/promises";
|
||||
import { access } from "node:fs/promises";
|
||||
import { existsSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { createInterface } from "node:readline/promises";
|
||||
@@ -8,8 +8,6 @@ import { fileURLToPath } from "node:url";
|
||||
|
||||
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const DEFAULT_CONFIG = "apps/worker/wrangler.toml";
|
||||
const DEFAULT_ENV_FILE = path.join(ROOT, ".env");
|
||||
const DEFAULT_ENV_EXAMPLE = path.join(ROOT, ".env.example");
|
||||
const BUN_CMD = (() => {
|
||||
if (process.env.BUN_BIN && existsSync(process.env.BUN_BIN)) {
|
||||
return process.env.BUN_BIN;
|
||||
@@ -159,56 +157,6 @@ const runCapture = (command, args, options = {}) =>
|
||||
const runBun = (args, options) => run(BUN_CMD, args, options);
|
||||
const runBunx = (args, options) => run(BUN_CMD, ["x", ...args], options);
|
||||
|
||||
const parseEnvLine = (line) => {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed || trimmed.startsWith("#")) {
|
||||
return null;
|
||||
}
|
||||
const idx = trimmed.indexOf("=");
|
||||
if (idx === -1) {
|
||||
return null;
|
||||
}
|
||||
const key = trimmed.slice(0, idx).trim();
|
||||
let value = trimmed.slice(idx + 1).trim();
|
||||
if (
|
||||
(value.startsWith("\"") && value.endsWith("\"")) ||
|
||||
(value.startsWith("'") && value.endsWith("'"))
|
||||
) {
|
||||
value = value.slice(1, -1);
|
||||
}
|
||||
return { key, value };
|
||||
};
|
||||
|
||||
const loadEnvFile = async (filePath) => {
|
||||
if (!existsSync(filePath)) {
|
||||
return [];
|
||||
}
|
||||
const raw = await readFile(filePath, "utf8");
|
||||
const lines = raw.split(/\r?\n/);
|
||||
for (const line of lines) {
|
||||
const parsed = parseEnvLine(line);
|
||||
if (!parsed) {
|
||||
continue;
|
||||
}
|
||||
if (process.env[parsed.key] === undefined) {
|
||||
process.env[parsed.key] = parsed.value;
|
||||
}
|
||||
}
|
||||
return lines;
|
||||
};
|
||||
|
||||
const ensureEnvFile = async (filePath, examplePath) => {
|
||||
if (existsSync(filePath)) {
|
||||
return;
|
||||
}
|
||||
if (existsSync(examplePath)) {
|
||||
const template = await readFile(examplePath, "utf8");
|
||||
await writeFile(filePath, template, "utf8");
|
||||
return;
|
||||
}
|
||||
await writeFile(filePath, "# 本地部署环境变量(自动生成)\n", "utf8");
|
||||
};
|
||||
|
||||
const promptChoice = async (rl, label, choices, defaultValue) => {
|
||||
const choicesText = choices.join("/");
|
||||
const defaultText = defaultValue ? ` [${defaultValue}]` : "";
|
||||
@@ -340,8 +288,6 @@ const main = async () => {
|
||||
const configPath = path.resolve(ROOT, options.config);
|
||||
|
||||
await access(configPath);
|
||||
await ensureEnvFile(DEFAULT_ENV_FILE, DEFAULT_ENV_EXAMPLE);
|
||||
await loadEnvFile(DEFAULT_ENV_FILE);
|
||||
|
||||
if (options.action === "init") {
|
||||
options.target = "both";
|
||||
|
||||
Reference in new issue
Block a user