fix: 修复设置系统脱节、队列计数漂移、资源泄露等全量问题
- 统一设置系统:create_scheduler_service 读取 DB 设置覆盖默认值 - 修复 ProxyRepository.update_score 误删所有无效代理的 SQL - ValidationQueue:修复 Worker 计数漂移与启动恢复任务饿死 - SchedulerService:移除 drain() 阻塞,主循环可正常响应 stop - TaskService:在调度器周期内自动清理过期任务,防止内存泄漏 - lifespan/conftest:规范关闭顺序,消除 Event loop closed 警告 - Repository:异常日志增加 exc_info,今日新增按 created_at 统计 - ValidatorService:防止 HTTP session 重复关闭,移除 SOCKS 多余 close - 前端:补全 pluginsStore.isEmpty,ProxyList 最低分数上限改为 100 - 删除 config.py 中冗余的 cors_origins_list property
This commit is contained in:
@@ -97,4 +97,8 @@ export const settingsAPI = {
|
||||
saveSettings: (data) => api.post('/api/settings', data)
|
||||
}
|
||||
|
||||
export const tasksAPI = {
|
||||
getTaskStatus: (taskId) => api.get(`/api/tasks/${taskId}`)
|
||||
}
|
||||
|
||||
export default api
|
||||
|
||||
@@ -1,4 +1,26 @@
|
||||
import { pluginsAPI } from '../api'
|
||||
import { pluginsAPI, tasksAPI } from '../api'
|
||||
|
||||
const POLL_INTERVAL = 1000
|
||||
const MAX_POLL_ATTEMPTS = 30
|
||||
|
||||
async function pollTaskStatus(taskId) {
|
||||
for (let i = 0; i < MAX_POLL_ATTEMPTS; i++) {
|
||||
await new Promise(resolve => setTimeout(resolve, POLL_INTERVAL))
|
||||
const response = await tasksAPI.getTaskStatus(taskId)
|
||||
if (response.code !== 200) {
|
||||
continue
|
||||
}
|
||||
const status = response.data.status
|
||||
if (status === 'completed' || status === 'failed') {
|
||||
return response
|
||||
}
|
||||
}
|
||||
return {
|
||||
code: 200,
|
||||
message: '爬取任务进行中,请稍后刷新查看结果',
|
||||
data: { task_id: taskId, status: 'running' }
|
||||
}
|
||||
}
|
||||
|
||||
export const pluginService = {
|
||||
async getPlugins() {
|
||||
@@ -18,10 +40,28 @@ export const pluginService = {
|
||||
},
|
||||
|
||||
async crawlPlugin(pluginId) {
|
||||
return pluginsAPI.crawlPlugin(pluginId)
|
||||
const startRes = await pluginsAPI.crawlPlugin(pluginId)
|
||||
if (startRes.code !== 200 || !startRes.data?.task_id) {
|
||||
return startRes
|
||||
}
|
||||
const finalRes = await pollTaskStatus(startRes.data.task_id)
|
||||
return {
|
||||
code: finalRes.code,
|
||||
message: finalRes.data?.message || finalRes.message,
|
||||
data: finalRes.data?.data || finalRes.data
|
||||
}
|
||||
},
|
||||
|
||||
async crawlAll() {
|
||||
return pluginsAPI.crawlAll()
|
||||
const startRes = await pluginsAPI.crawlAll()
|
||||
if (startRes.code !== 200 || !startRes.data?.task_id) {
|
||||
return startRes
|
||||
}
|
||||
const finalRes = await pollTaskStatus(startRes.data.task_id)
|
||||
return {
|
||||
code: finalRes.code,
|
||||
message: finalRes.data?.message || finalRes.message,
|
||||
data: finalRes.data?.data || finalRes.data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ export const usePluginsStore = defineStore('plugins', () => {
|
||||
// ==================== Getters ====================
|
||||
const enabledCount = computed(() => plugins.value.filter(p => p.enabled).length)
|
||||
const totalCount = computed(() => plugins.value.length)
|
||||
const isEmpty = computed(() => !loading.value && plugins.value.length === 0)
|
||||
|
||||
// ==================== Actions ====================
|
||||
|
||||
@@ -97,6 +98,7 @@ export const usePluginsStore = defineStore('plugins', () => {
|
||||
// Getters
|
||||
enabledCount,
|
||||
totalCount,
|
||||
isEmpty,
|
||||
// Actions
|
||||
fetchPlugins,
|
||||
togglePlugin,
|
||||
|
||||
@@ -132,8 +132,8 @@ export const useProxyStore = defineStore('proxy', () => {
|
||||
try {
|
||||
const response = await proxyService.export(format, protocol)
|
||||
|
||||
// 创建下载链接
|
||||
const url = window.URL.createObjectURL(new Blob([response]))
|
||||
// response 已经是 Blob(axios 配置了 responseType: 'blob'),直接创建下载链接
|
||||
const url = window.URL.createObjectURL(response)
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.setAttribute('download', `proxies.${format}`)
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<el-input-number
|
||||
v-model="filterForm.minScore"
|
||||
:min="0"
|
||||
:max="10"
|
||||
:max="100"
|
||||
style="width: 120px"
|
||||
@change="handleSearch"
|
||||
/>
|
||||
@@ -190,7 +190,7 @@ async function fetchProxies() {
|
||||
}
|
||||
abortController = new AbortController()
|
||||
|
||||
await proxyStore.fetchProxies({
|
||||
const success = await proxyStore.fetchProxies({
|
||||
page: currentPage.value,
|
||||
page_size: pageSize.value,
|
||||
protocol: filterForm.protocol || null,
|
||||
@@ -200,6 +200,9 @@ async function fetchProxies() {
|
||||
}, abortController.signal)
|
||||
|
||||
abortController = null
|
||||
if (!success) {
|
||||
ElMessage.error('获取代理列表失败')
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 事件处理 ====================
|
||||
|
||||
Reference in New Issue
Block a user