chore(repo): initialize team collaboration repository
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
"""事件溯源写入。"""
|
||||
|
||||
from .recorder import append_event
|
||||
|
||||
__all__ = ["append_event"]
|
||||
@@ -0,0 +1,54 @@
|
||||
"""Run 事件唯一写入口,同时维护当前状态投影。"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from ..engine.states import assert_run_transition
|
||||
from ..enums import EventSource, Severity
|
||||
from ..models import Run, RunEvent, utcnow
|
||||
|
||||
|
||||
async def append_event(
|
||||
session: AsyncSession,
|
||||
run: Run,
|
||||
kind: str,
|
||||
message: str,
|
||||
*,
|
||||
source: str = EventSource.CONTROL_PLANE.value,
|
||||
severity: str = Severity.INFO.value,
|
||||
payload: Optional[Dict[str, Any]] = None,
|
||||
target_state: Optional[str] = None,
|
||||
projection: Optional[Dict[str, Any]] = None,
|
||||
idempotency_key: Optional[str] = None,
|
||||
step_id: Optional[str] = None,
|
||||
loop_index: Optional[int] = None,
|
||||
) -> RunEvent:
|
||||
if target_state is not None and target_state != run.state:
|
||||
assert_run_transition(run.state, target_state)
|
||||
|
||||
run.event_seq += 1
|
||||
event = RunEvent(
|
||||
run_id=run.id,
|
||||
seq=run.event_seq,
|
||||
ts=utcnow(),
|
||||
source=source,
|
||||
kind=kind,
|
||||
severity=severity,
|
||||
message=message,
|
||||
payload=payload or {},
|
||||
idempotency_key=idempotency_key,
|
||||
step_id=step_id,
|
||||
loop_index=loop_index,
|
||||
)
|
||||
session.add(event)
|
||||
|
||||
if target_state is not None:
|
||||
run.state = target_state
|
||||
for key, value in (projection or {}).items():
|
||||
if not hasattr(run, key):
|
||||
raise AttributeError("Run 不存在投影字段: {0}".format(key))
|
||||
setattr(run, key, value)
|
||||
await session.flush()
|
||||
return event
|
||||
Reference in New Issue
Block a user