fix(automation): enforce durable alert closure
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m32s
CD Pipeline / build-and-deploy (push) Successful in 8m2s
CD Pipeline / post-deploy-checks (push) Successful in 2m22s
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m32s
CD Pipeline / build-and-deploy (push) Successful in 8m2s
CD Pipeline / post-deploy-checks (push) Successful in 2m22s
Restore D037 durable incident readback without weakening database failure semantics. Fence Agent99 dispatch and terminal learning to canonical identities, durable leases, verifier receipts, and reconciler-owned checkpoints. Drain backup and restore legacy receipts in bounded cohorts with strict transport, claim, projection, and no-false-green controls. Keep SSH service refusal visible while separating it from broker network-policy reachability.
This commit is contained in:
@@ -660,9 +660,20 @@ class KnowledgeService:
|
||||
# I1: 持有背景 Task 引用,防止 GC 提前回收
|
||||
self._pending_tasks: set[asyncio.Task] = set() # type: ignore[type-arg]
|
||||
|
||||
async def create_entry(self, data: KnowledgeEntryCreate) -> KnowledgeEntry:
|
||||
async def create_entry(
|
||||
self,
|
||||
data: KnowledgeEntryCreate,
|
||||
*,
|
||||
project_id: str | None = None,
|
||||
schedule_embedding: bool = True,
|
||||
) -> KnowledgeEntry:
|
||||
"""建立知識條目,建立後背景自動產生 embedding"""
|
||||
async with get_db_context() as db:
|
||||
context = (
|
||||
get_db_context(project_id)
|
||||
if project_id is not None
|
||||
else get_db_context()
|
||||
)
|
||||
async with context as db:
|
||||
repo: IKnowledgeRepository = KnowledgeDBRepository(db)
|
||||
entry = await repo.create(data)
|
||||
logger.info(
|
||||
@@ -673,17 +684,33 @@ class KnowledgeService:
|
||||
)
|
||||
|
||||
# 背景產生 embedding (不阻塞回應);持有引用防 GC 回收
|
||||
task = asyncio.create_task(self._embed_entry(entry.id, data.title, data.content))
|
||||
self._pending_tasks.add(task)
|
||||
task.add_done_callback(self._pending_tasks.discard)
|
||||
if schedule_embedding:
|
||||
task = asyncio.create_task(
|
||||
self._embed_entry(
|
||||
entry.id,
|
||||
data.title,
|
||||
data.content,
|
||||
project_id=project_id,
|
||||
)
|
||||
)
|
||||
self._pending_tasks.add(task)
|
||||
task.add_done_callback(self._pending_tasks.discard)
|
||||
return entry
|
||||
|
||||
async def _embed_entry(self, entry_id: str, title: str, content: str) -> None:
|
||||
async def _embed_entry(
|
||||
self,
|
||||
entry_id: str,
|
||||
title: str,
|
||||
content: str,
|
||||
*,
|
||||
project_id: str | None = None,
|
||||
) -> None:
|
||||
"""背景任務:產生並儲存 embedding"""
|
||||
await self.ensure_entry_embedding(
|
||||
entry_id,
|
||||
title,
|
||||
content,
|
||||
project_id=project_id,
|
||||
)
|
||||
|
||||
async def ensure_entry_embedding(
|
||||
|
||||
Reference in New Issue
Block a user