feat: sed-мутации датасетов, правки миграции и фиксы
- Dataset viewer: sed-замена (find→replace) по всем/выбранным/текущим датасетам с обязательным визуальным предпросмотром и целями (sql/metrics/yaml); сохранение и выбор именованных правил (sedRules store + SedRuleEditor). - Migration: literal-замена в dataset YAML при переносе; рескан ID чартов/датасетов перед миграцией + метрика средней длительности синка (GET /migration/sync-stats); логическая группировка опций (маппинги БД, сервер изменений, rescan) под галочками. - Fix: дашборды хаба скрывались дефолтным профиль-фильтром show_only_slug_dashboards=true (теперь false); мастер миграции не грузил дашборды предзаполненного источника; потеря терминального task_status из-за утечки pending-корутин в /ws/logs (панель результата не появлялась); горизонтальный скролл в MappingTable; чистая per-env ошибка в mapping coverage. - Backend: record_sync_duration + alembic-миграция sync-duration; literal_replace модуль.
This commit is contained in:
@@ -996,10 +996,17 @@ async def websocket_endpoint(websocket: WebSocket, task_id: str, source: str = N
|
||||
while True:
|
||||
log_task = asyncio.create_task(log_queue.get())
|
||||
status_task = asyncio.create_task(status_queue.get())
|
||||
done, _ = await asyncio.wait(
|
||||
done, pending = await asyncio.wait(
|
||||
[log_task, status_task],
|
||||
return_when=asyncio.FIRST_COMPLETED,
|
||||
)
|
||||
# @INVARIANT Cancel the not-yet-completed waiter BEFORE the next iteration.
|
||||
# Without this, each loop leaks a pending queue.get() coroutine that
|
||||
# consumes the NEXT item (e.g. the terminal task_status event), so the
|
||||
# completion broadcast is silently swallowed and the client never sees
|
||||
# the structured result — the result panel stays hidden after a task ends.
|
||||
for pending_task in pending:
|
||||
pending_task.cancel()
|
||||
for coro in done:
|
||||
result = coro.result()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user