fix: address code review feedback - startup validation, error context, security notes
- Fail fast on startup if ZY_CN_RELAY_API_KEY is not configured - Add model endpoint context to error messages for debugging - Make API timeout configurable via environment variable - Deduplicate health check curl in workflow - Add security note about VPN-encrypted relay channel Agent-Logs-Url: https://github.com/qinfendebingshuo/guanghulab/sessions/f6db708e-8b10-4339-b48f-db5f111ae5cd Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com>
This commit is contained in:
parent
91c957d85e
commit
6146dd3aea
|
|
@ -111,9 +111,10 @@ jobs:
|
||||||
|
|
||||||
# 健康检查
|
# 健康检查
|
||||||
sleep 3
|
sleep 3
|
||||||
if curl -sf http://127.0.0.1:3900/health > /dev/null 2>&1; then
|
HEALTH_RESULT=$(curl -s http://127.0.0.1:3900/health 2>/dev/null || echo "")
|
||||||
|
if [ -n "$HEALTH_RESULT" ]; then
|
||||||
echo "✅ CN LLM Relay 健康检查通过"
|
echo "✅ CN LLM Relay 健康检查通过"
|
||||||
curl -s http://127.0.0.1:3900/health | head -c 500
|
echo "$HEALTH_RESULT" | head -c 500
|
||||||
else
|
else
|
||||||
echo "⚠️ 健康检查未通过 · 查看日志"
|
echo "⚠️ 健康检查未通过 · 查看日志"
|
||||||
pm2 logs cn-llm-relay --lines 20 --nostream
|
pm2 logs cn-llm-relay --lines 20 --nostream
|
||||||
|
|
|
||||||
|
|
@ -208,6 +208,10 @@ function callDomesticLLM(modelConfig, messages) {
|
||||||
* 通过广州CN中继调用国内模型API
|
* 通过广州CN中继调用国内模型API
|
||||||
* 架构: SG(新加坡) → 广州(ZY-SVR-003):3900 → 国内API
|
* 架构: SG(新加坡) → 广州(ZY-SVR-003):3900 → 国内API
|
||||||
* 对称于硅谷Claude中继: SG → SV(SSH隧道) → Claude API
|
* 对称于硅谷Claude中继: SG → SV(SSH隧道) → Claude API
|
||||||
|
*
|
||||||
|
* 安全: SG↔广州通信走HTTP但通过已有的VPN/内网隧道加密
|
||||||
|
* (setup-cn-relay.sh 建立的 CN:2053→SG:443 Xray通道)
|
||||||
|
* 中继鉴权密钥通过 Bearer Token 传递
|
||||||
*/
|
*/
|
||||||
function callViaCNRelay(messages, selected, fallbackOrder) {
|
function callViaCNRelay(messages, selected, fallbackOrder) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
@ -250,7 +254,7 @@ function callViaCNRelay(messages, selected, fallbackOrder) {
|
||||||
|
|
||||||
req.setTimeout(CN_RELAY_TIMEOUT, () => {
|
req.setTimeout(CN_RELAY_TIMEOUT, () => {
|
||||||
req.destroy();
|
req.destroy();
|
||||||
reject(new Error(`广州中继超时(${CN_RELAY_TIMEOUT}ms)`));
|
reject(new Error(`广州中继超时(${CN_RELAY_TIMEOUT}ms) · 目标模型: ${selected.id}`));
|
||||||
});
|
});
|
||||||
req.on('error', (err) => {
|
req.on('error', (err) => {
|
||||||
reject(new Error(`广州中继连接失败: ${err.message}`));
|
reject(new Error(`广州中继连接失败: ${err.message}`));
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,16 @@ const app = express();
|
||||||
const PORT = process.env.RELAY_PORT || 3900;
|
const PORT = process.env.RELAY_PORT || 3900;
|
||||||
const RELAY_API_KEY = process.env.ZY_CN_RELAY_API_KEY || '';
|
const RELAY_API_KEY = process.env.ZY_CN_RELAY_API_KEY || '';
|
||||||
|
|
||||||
|
// 启动时校验: 鉴权密钥必须配置
|
||||||
|
if (!RELAY_API_KEY) {
|
||||||
|
console.error('[CN中继] ❌ ZY_CN_RELAY_API_KEY 未配置 · 服务拒绝启动');
|
||||||
|
console.error('[CN中继] 请在 .env.relay 中设置 ZY_CN_RELAY_API_KEY');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// API请求超时(可通过环境变量调整)
|
||||||
|
const API_TIMEOUT_MS = parseInt(process.env.ZY_CN_API_TIMEOUT || '60000', 10);
|
||||||
|
|
||||||
// ─── 国内模型配置 ───
|
// ─── 国内模型配置 ───
|
||||||
const DOMESTIC_MODELS = {
|
const DOMESTIC_MODELS = {
|
||||||
ds: {
|
ds: {
|
||||||
|
|
@ -162,21 +172,23 @@ function callDomesticAPI(modelConfig, apiKey, requestBody) {
|
||||||
try {
|
try {
|
||||||
const body = JSON.parse(Buffer.concat(chunks).toString());
|
const body = JSON.parse(Buffer.concat(chunks).toString());
|
||||||
if (body.error) {
|
if (body.error) {
|
||||||
reject(new Error(body.error.message || JSON.stringify(body.error)));
|
reject(new Error(`${modelConfig.endpoint}: ${body.error.message || JSON.stringify(body.error)}`));
|
||||||
} else {
|
} else {
|
||||||
resolve(body);
|
resolve(body);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
reject(new Error('响应解析失败'));
|
reject(new Error(`${modelConfig.endpoint} 响应解析失败 (HTTP ${res.statusCode})`));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
req.setTimeout(60000, () => {
|
req.setTimeout(API_TIMEOUT_MS, () => {
|
||||||
req.destroy();
|
req.destroy();
|
||||||
reject(new Error('国内API请求超时(60s)'));
|
reject(new Error(`${modelConfig.endpoint} 请求超时(${API_TIMEOUT_MS}ms)`));
|
||||||
|
});
|
||||||
|
req.on('error', (err) => {
|
||||||
|
reject(new Error(`${modelConfig.endpoint} 连接失败: ${err.message}`));
|
||||||
});
|
});
|
||||||
req.on('error', reject);
|
|
||||||
req.write(bodyStr);
|
req.write(bodyStr);
|
||||||
req.end();
|
req.end();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue