Compare commits

..

3 Commits

Author SHA1 Message Date
fish 9fd0116dec 后台同步任务超时后可覆盖启动,前端阻塞时显示提示而非静默隐藏
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-25 21:40:11 +08:00
fish ab9b132c69 更新数据库文件
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-25 21:34:34 +08:00
fish 1b0f906640 后台同步异常时前端显示错误提示,不再卡住页面
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-25 21:34:04 +08:00
3 changed files with 37 additions and 4 deletions
+10 -3
View File
@@ -1,13 +1,16 @@
"""Data collector — fetch OHLCV from akshare and upsert into daily_bars."""
import threading
import time
from datetime import date
from app.database import SessionLocal
from app.models import DailyBar, Contract
from app.engine.lock_strategy import compute_amp_5d
_progress = {"running": False, "label": "", "done": 0, "total": 0, "result": 0, "finished": False}
_progress = {"running": False, "label": "", "done": 0, "total": 0, "result": 0, "finished": False, "error": "", "started_at": 0}
_lock = threading.Lock()
STALE_SECONDS = 120
def get_progress() -> dict:
with _lock:
@@ -16,13 +19,17 @@ def get_progress() -> dict:
def _start_bg(target, label):
with _lock:
if _progress["running"]:
now = time.time()
if _progress["running"] and (now - _progress["started_at"]) < STALE_SECONDS:
return False
_progress.update(running=True, finished=False, label=label, done=0, total=0)
_progress.update(running=True, finished=False, label=label, done=0, total=0, error="", started_at=now)
def _run():
try:
target()
except Exception as e:
with _lock:
_progress["error"] = str(e)
finally:
with _lock:
_progress["running"] = False
+27 -1
View File
@@ -192,6 +192,12 @@
</div>
<script>
function escapeHtml(s) {
var d = document.createElement('div');
d.appendChild(document.createTextNode(s));
return d.innerHTML;
}
var syncTimer = null;
var progressShownAt = 0;
@@ -218,6 +224,19 @@ function pollProgress() {
document.getElementById('sync-progress-pct').textContent = pct + '%';
document.getElementById('sync-progress-label').textContent = data.label;
if (data.error) {
clearInterval(syncTimer);
syncTimer = null;
document.getElementById('sync-progress-bar').style.background = 'var(--danger)';
document.getElementById('sync-progress-label').innerHTML =
'<span style="color:var(--danger-fg);">✕ ' + escapeHtml(data.label) + '</span>' +
'<span style="display:block;font-size:0.78rem;color:var(--danger-fg);margin-top:4px;">' + escapeHtml(data.error) + '</span>';
document.getElementById('sync-progress-pct').textContent = '';
document.getElementById('sync-progress').insertAdjacentHTML('beforeend',
'<button onclick="hideProgress()" style="display:block;margin-top:10px;padding:4px 14px;border:1px solid var(--border);border-radius:5px;background:var(--surface);color:var(--fg);cursor:pointer;font-size:0.8rem;">关闭</button>');
return;
}
if (data.finished) {
var elapsed = Date.now() - progressShownAt;
var delay = elapsed < 1000 ? 1000 - elapsed : 0;
@@ -246,7 +265,14 @@ function startSync(url) {
fetch(url, { method: 'POST' })
.then(function(r) { return r.json(); })
.then(function(data) {
if (!data.ok) { hideProgress(); return; }
if (!data.ok) {
document.getElementById('sync-progress-label').textContent = '已有同步任务进行中,请稍后再试';
document.getElementById('sync-progress-pct').textContent = '';
document.getElementById('sync-progress-bar').style.width = '0%';
document.getElementById('sync-progress').insertAdjacentHTML('beforeend',
'<button onclick="hideProgress()" style="display:block;margin-top:10px;padding:4px 14px;border:1px solid var(--border);border-radius:5px;background:var(--surface);color:var(--fg);cursor:pointer;font-size:0.8rem;">关闭</button>');
return;
}
syncTimer = setInterval(pollProgress, 500);
});
}
BIN
View File
Binary file not shown.