mirror of
https://github.com/snailyp/gemini-balance.git
synced 2026-09-04 23:19:17 +08:00
refactor(scheduler): 优化定时任务配置和时间处理
- 支持CHECK_INTERVAL_HOURS设置为0以禁用密钥检查任务 - 调整日志清理任务执行时间从凌晨3点改为0点 - 移除timezone依赖,使用本地时间处理 - 优化代码格式和导入顺序 - 为配置编辑器添加CHECK_INTERVAL_HOURS输入验证 - 改进UI布局,为关键配置项添加警告提示
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
|
||||
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||||
|
||||
from app.config.config import settings
|
||||
@@ -6,9 +5,9 @@ from app.domain.gemini_models import GeminiContent, GeminiRequest
|
||||
from app.log.logger import Logger
|
||||
from app.service.chat.gemini_chat_service import GeminiChatService
|
||||
from app.service.error_log.error_log_service import delete_old_error_logs
|
||||
from app.service.files.files_service import get_files_service
|
||||
from app.service.key.key_manager import get_key_manager_instance
|
||||
from app.service.request_log.request_log_service import delete_old_request_logs_task
|
||||
from app.service.files.files_service import get_files_service
|
||||
from app.utils.helpers import redact_key_for_logging
|
||||
|
||||
logger = Logger.setup_logger("scheduler")
|
||||
@@ -106,15 +105,16 @@ async def cleanup_expired_files():
|
||||
try:
|
||||
files_service = await get_files_service()
|
||||
deleted_count = await files_service.cleanup_expired_files()
|
||||
|
||||
|
||||
if deleted_count > 0:
|
||||
logger.info(f"Successfully cleaned up {deleted_count} expired files.")
|
||||
else:
|
||||
logger.info("No expired files to clean up.")
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"An error occurred during the scheduled file cleanup: {str(e)}", exc_info=True
|
||||
f"An error occurred during the scheduled file cleanup: {str(e)}",
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -122,44 +122,45 @@ def setup_scheduler():
|
||||
"""设置并启动 APScheduler"""
|
||||
scheduler = AsyncIOScheduler(timezone=str(settings.TIMEZONE)) # 从配置读取时区
|
||||
# 添加检查失败密钥的定时任务
|
||||
scheduler.add_job(
|
||||
check_failed_keys,
|
||||
"interval",
|
||||
hours=settings.CHECK_INTERVAL_HOURS,
|
||||
id="check_failed_keys_job",
|
||||
name="Check Failed API Keys",
|
||||
)
|
||||
logger.info(
|
||||
f"Key check job scheduled to run every {settings.CHECK_INTERVAL_HOURS} hour(s)."
|
||||
)
|
||||
if settings.CHECK_INTERVAL_HOURS != 0:
|
||||
scheduler.add_job(
|
||||
check_failed_keys,
|
||||
"interval",
|
||||
hours=settings.CHECK_INTERVAL_HOURS,
|
||||
id="check_failed_keys_job",
|
||||
name="Check Failed API Keys",
|
||||
)
|
||||
logger.info(
|
||||
f"Key check job scheduled to run every {settings.CHECK_INTERVAL_HOURS} hour(s)."
|
||||
)
|
||||
|
||||
# 新增:添加自动删除错误日志的定时任务,每天凌晨3点执行
|
||||
# 新增:添加自动删除错误日志的定时任务,每天凌晨0点执行
|
||||
scheduler.add_job(
|
||||
delete_old_error_logs,
|
||||
"cron",
|
||||
hour=3,
|
||||
hour=0,
|
||||
minute=0,
|
||||
id="delete_old_error_logs_job",
|
||||
name="Delete Old Error Logs",
|
||||
)
|
||||
logger.info("Auto-delete error logs job scheduled to run daily at 3:00 AM.")
|
||||
|
||||
# 新增:添加自动删除请求日志的定时任务,每天凌晨3点05分执行
|
||||
# 新增:添加自动删除请求日志的定时任务,每天凌晨0点执行
|
||||
scheduler.add_job(
|
||||
delete_old_request_logs_task,
|
||||
"cron",
|
||||
hour=3,
|
||||
minute=5,
|
||||
hour=0,
|
||||
minute=0,
|
||||
id="delete_old_request_logs_job",
|
||||
name="Delete Old Request Logs",
|
||||
)
|
||||
logger.info(
|
||||
f"Auto-delete request logs job scheduled to run daily at 3:05 AM, if enabled and AUTO_DELETE_REQUEST_LOGS_DAYS is set to {settings.AUTO_DELETE_REQUEST_LOGS_DAYS} days."
|
||||
)
|
||||
|
||||
|
||||
# 新增:添加文件过期清理的定时任务,每小时执行一次
|
||||
if getattr(settings, 'FILES_CLEANUP_ENABLED', True):
|
||||
cleanup_interval = getattr(settings, 'FILES_CLEANUP_INTERVAL_HOURS', 1)
|
||||
if getattr(settings, "FILES_CLEANUP_ENABLED", True):
|
||||
cleanup_interval = getattr(settings, "FILES_CLEANUP_INTERVAL_HOURS", 1)
|
||||
scheduler.add_job(
|
||||
cleanup_expired_files,
|
||||
"interval",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from sqlalchemy import delete, func, select
|
||||
@@ -28,7 +28,7 @@ async def delete_old_error_logs():
|
||||
)
|
||||
return
|
||||
|
||||
cutoff_date = datetime.now(timezone.utc) - timedelta(days=days_to_keep)
|
||||
cutoff_date = datetime.now() - timedelta(days=days_to_keep)
|
||||
|
||||
logger.info(
|
||||
f"Attempting to delete error logs older than {days_to_keep} days (before {cutoff_date.strftime('%Y-%m-%d %H:%M:%S %Z')})."
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
Service for request log operations.
|
||||
"""
|
||||
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from sqlalchemy import delete
|
||||
|
||||
from app.database.connection import database
|
||||
from app.config.config import settings
|
||||
from app.database.connection import database
|
||||
from app.database.models import RequestLog
|
||||
from app.log.logger import get_request_log_logger
|
||||
|
||||
@@ -30,7 +30,7 @@ async def delete_old_request_logs_task():
|
||||
)
|
||||
|
||||
try:
|
||||
cutoff_date = datetime.now(timezone.utc) - timedelta(days=days_to_keep)
|
||||
cutoff_date = datetime.now() - timedelta(days=days_to_keep)
|
||||
|
||||
query = delete(RequestLog).where(RequestLog.request_time < cutoff_date)
|
||||
|
||||
|
||||
@@ -104,6 +104,24 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
});
|
||||
}
|
||||
|
||||
// 检查间隔小时数输入控制
|
||||
const checkIntervalInput = document.getElementById("CHECK_INTERVAL_HOURS");
|
||||
if (checkIntervalInput) {
|
||||
checkIntervalInput.addEventListener("input", function () {
|
||||
let value = parseFloat(this.value);
|
||||
if (isNaN(value) || value < 0) {
|
||||
this.value = 0;
|
||||
}
|
||||
});
|
||||
|
||||
checkIntervalInput.addEventListener("change", function () {
|
||||
let value = parseFloat(this.value);
|
||||
if (isNaN(value) || value < 0) {
|
||||
this.value = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Toggle switch events
|
||||
const toggleSwitches = document.querySelectorAll(".toggle-switch");
|
||||
toggleSwitches.forEach((toggleSwitch) => {
|
||||
|
||||
@@ -1416,25 +1416,31 @@ endblock %} {% block head_extra_styles %}
|
||||
</div>
|
||||
|
||||
<!-- 启用代码执行工具 -->
|
||||
<div class="mb-6 flex items-center justify-between">
|
||||
<label
|
||||
for="TOOLS_CODE_EXECUTION_ENABLED"
|
||||
class="font-semibold text-gray-700"
|
||||
>启用代码执行工具</label
|
||||
>
|
||||
<div
|
||||
class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="TOOLS_CODE_EXECUTION_ENABLED"
|
||||
id="TOOLS_CODE_EXECUTION_ENABLED"
|
||||
class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer"
|
||||
/>
|
||||
<div class="mb-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<label
|
||||
for="TOOLS_CODE_EXECUTION_ENABLED"
|
||||
class="toggle-label block overflow-hidden h-6 rounded-full bg-gray-300 cursor-pointer"
|
||||
></label>
|
||||
class="font-semibold text-gray-700"
|
||||
>启用代码执行工具</label
|
||||
>
|
||||
<div
|
||||
class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="TOOLS_CODE_EXECUTION_ENABLED"
|
||||
id="TOOLS_CODE_EXECUTION_ENABLED"
|
||||
class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer"
|
||||
/>
|
||||
<label
|
||||
for="TOOLS_CODE_EXECUTION_ENABLED"
|
||||
class="toggle-label block overflow-hidden h-6 rounded-full bg-gray-300 cursor-pointer"
|
||||
></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="warning-text">
|
||||
<i class="fas fa-exclamation-triangle"></i>
|
||||
<span>启用代码执行工具与大多数工具调用冲突,不建议开启</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2007,25 +2013,31 @@ endblock %} {% block head_extra_styles %}
|
||||
</h2>
|
||||
|
||||
<!-- 启用流式输出优化 -->
|
||||
<div class="mb-6 flex items-center justify-between">
|
||||
<label
|
||||
for="STREAM_OPTIMIZER_ENABLED"
|
||||
class="font-semibold text-gray-700"
|
||||
>启用流式输出优化</label
|
||||
>
|
||||
<div
|
||||
class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="STREAM_OPTIMIZER_ENABLED"
|
||||
id="STREAM_OPTIMIZER_ENABLED"
|
||||
class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer"
|
||||
/>
|
||||
<div class="mb-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<label
|
||||
for="STREAM_OPTIMIZER_ENABLED"
|
||||
class="toggle-label block overflow-hidden h-6 rounded-full bg-gray-300 cursor-pointer"
|
||||
></label>
|
||||
class="font-semibold text-gray-700"
|
||||
>启用流式输出优化</label
|
||||
>
|
||||
<div
|
||||
class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="STREAM_OPTIMIZER_ENABLED"
|
||||
id="STREAM_OPTIMIZER_ENABLED"
|
||||
class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer"
|
||||
/>
|
||||
<label
|
||||
for="STREAM_OPTIMIZER_ENABLED"
|
||||
class="toggle-label block overflow-hidden h-6 rounded-full bg-gray-300 cursor-pointer"
|
||||
></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="warning-text">
|
||||
<i class="fas fa-exclamation-triangle"></i>
|
||||
<span>开启流式优化会在一定程度上减速返回,不建议开启</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2185,31 +2197,18 @@ endblock %} {% block head_extra_styles %}
|
||||
for="CHECK_INTERVAL_HOURS"
|
||||
class="block font-semibold mb-2 text-gray-700"
|
||||
>检查间隔(小时)
|
||||
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="定时检查密钥状态的间隔时间(单位:小时)"></i>
|
||||
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="定时检查密钥状态的间隔时间(单位:小时),设置为0时不进行定时检查"></i>
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
id="CHECK_INTERVAL_HOURS"
|
||||
name="CHECK_INTERVAL_HOURS"
|
||||
min="1"
|
||||
min="0"
|
||||
step="1"
|
||||
class="w-full px-4 py-3 rounded-lg form-input-themed"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 时区 -->
|
||||
<div class="mb-6">
|
||||
<label for="TIMEZONE" class="block font-semibold mb-2 text-gray-700"
|
||||
>时区
|
||||
<i class="fas fa-question-circle text-gray-400 ml-1 cursor-help" title="定时任务使用的时区,格式如 Asia/Shanghai 或 UTC"></i>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="TIMEZONE"
|
||||
name="TIMEZONE"
|
||||
placeholder="例如: Asia/Shanghai"
|
||||
class="w-full px-4 py-3 rounded-lg form-input-themed"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 日志配置 -->
|
||||
|
||||
Reference in New Issue
Block a user