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.""" """Data collector — fetch OHLCV from akshare and upsert into daily_bars."""
import threading import threading
import time
from datetime import date from datetime import date
from app.database import SessionLocal from app.database import SessionLocal
from app.models import DailyBar, Contract from app.models import DailyBar, Contract
from app.engine.lock_strategy import compute_amp_5d 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() _lock = threading.Lock()
STALE_SECONDS = 120
def get_progress() -> dict: def get_progress() -> dict:
with _lock: with _lock:
@@ -16,13 +19,17 @@ def get_progress() -> dict:
def _start_bg(target, label): def _start_bg(target, label):
with _lock: with _lock:
if _progress["running"]: now = time.time()
if _progress["running"] and (now - _progress["started_at"]) < STALE_SECONDS:
return False 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(): def _run():
try: try:
target() target()
except Exception as e:
with _lock:
_progress["error"] = str(e)
finally: finally:
with _lock: with _lock:
_progress["running"] = False _progress["running"] = False
+27 -1
View File
@@ -192,6 +192,12 @@
</div> </div>
<script> <script>
function escapeHtml(s) {
var d = document.createElement('div');
d.appendChild(document.createTextNode(s));
return d.innerHTML;
}
var syncTimer = null; var syncTimer = null;
var progressShownAt = 0; var progressShownAt = 0;
@@ -218,6 +224,19 @@ function pollProgress() {
document.getElementById('sync-progress-pct').textContent = pct + '%'; document.getElementById('sync-progress-pct').textContent = pct + '%';
document.getElementById('sync-progress-label').textContent = data.label; 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) { if (data.finished) {
var elapsed = Date.now() - progressShownAt; var elapsed = Date.now() - progressShownAt;
var delay = elapsed < 1000 ? 1000 - elapsed : 0; var delay = elapsed < 1000 ? 1000 - elapsed : 0;
@@ -246,7 +265,14 @@ function startSync(url) {
fetch(url, { method: 'POST' }) fetch(url, { method: 'POST' })
.then(function(r) { return r.json(); }) .then(function(r) { return r.json(); })
.then(function(data) { .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); syncTimer = setInterval(pollProgress, 500);
}); });
} }
BIN
View File
Binary file not shown.