feat: 首次推送到Gitea - 完整项目代码 + 安全加固 + 知识库
This commit is contained in:
+25
-12
@@ -1,24 +1,37 @@
|
||||
// 简易熔断器:连续失败 N 次后,在冷却期内直接抛错
|
||||
const circuitState = { failures: 0, openUntil: 0 };
|
||||
// 简易熔断器:按 label 分桶,连续失败 N 次后,在冷却期内直接抛错
|
||||
// 不同 label(如 deepseek / github / http)各自独立熔断,互不影响
|
||||
const circuits = new Map(); // label -> { failures, openUntil }
|
||||
const CIRCUIT_THRESHOLD = 5; // 连续失败 5 次触发熔断
|
||||
const CIRCUIT_COOLDOWN_MS = 60000; // 熔断冷却 60 秒
|
||||
|
||||
function getCircuit(label) {
|
||||
let c = circuits.get(label);
|
||||
if (!c) {
|
||||
c = { failures: 0, openUntil: 0 };
|
||||
circuits.set(label, c);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
function checkCircuit(label) {
|
||||
if (Date.now() < circuitState.openUntil) {
|
||||
throw new Error(`[circuit-breaker] ${label} 熔断中,${Math.ceil((circuitState.openUntil - Date.now()) / 1000)}s 后恢复`);
|
||||
const c = getCircuit(label);
|
||||
if (Date.now() < c.openUntil) {
|
||||
throw new Error(`[circuit-breaker] ${label} 熔断中,${Math.ceil((c.openUntil - Date.now()) / 1000)}s 后恢复`);
|
||||
}
|
||||
}
|
||||
|
||||
function recordSuccess() {
|
||||
circuitState.failures = 0;
|
||||
circuitState.openUntil = 0;
|
||||
function recordSuccess(label) {
|
||||
const c = getCircuit(label);
|
||||
c.failures = 0;
|
||||
c.openUntil = 0;
|
||||
}
|
||||
|
||||
function recordFailure(label) {
|
||||
circuitState.failures++;
|
||||
if (circuitState.failures >= CIRCUIT_THRESHOLD) {
|
||||
circuitState.openUntil = Date.now() + CIRCUIT_COOLDOWN_MS;
|
||||
console.warn(` 🔌 [circuit-breaker] ${label} 连续失败 ${circuitState.failures} 次,熔断 ${CIRCUIT_COOLDOWN_MS / 1000}s`);
|
||||
const c = getCircuit(label);
|
||||
c.failures++;
|
||||
if (c.failures >= CIRCUIT_THRESHOLD) {
|
||||
c.openUntil = Date.now() + CIRCUIT_COOLDOWN_MS;
|
||||
console.warn(` 🔌 [circuit-breaker] ${label} 连续失败 ${c.failures} 次,熔断 ${CIRCUIT_COOLDOWN_MS / 1000}s`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +41,7 @@ async function withRetry(fn, { maxRetries = 3, baseDelay = 1000, label = "operat
|
||||
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||||
try {
|
||||
const result = await fn();
|
||||
recordSuccess();
|
||||
recordSuccess(label);
|
||||
return result;
|
||||
} catch (error) {
|
||||
lastError = error;
|
||||
|
||||
Reference in New Issue
Block a user