Take the engine off the path node code imports from, and let it stop
The worker script is handed to the interpreter by path, so app/flow was sys.path[0] for every node: `import queue` got the engine's. It now drops its own directory before anything else imports, and runs with the deployment's credentials scrubbed out of its environment. Also: reload builds off the event loop, the pool wakes what is blocked on it when it stops, a refused metrics flush is kept for the next one rather than dropped, and the cascade events are paired through failures. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017MeiWk3Yq12n2pTvnQWYvt
This commit is contained in:
@@ -126,6 +126,56 @@ def test_events_become_rollups_failures_runs_and_audit(db: Session) -> None:
|
||||
assert open_run.status == "running"
|
||||
|
||||
|
||||
def test_a_flush_the_database_refused_is_written_by_the_next_one(
|
||||
db: Session, monkeypatch
|
||||
) -> None:
|
||||
collector = MetricsCollector(EventBus())
|
||||
ts = datetime.now(timezone.utc).replace(second=0, microsecond=0).timestamp()
|
||||
collector.handle(
|
||||
{
|
||||
"type": "audit",
|
||||
"action": "held back",
|
||||
"flow": FLOW,
|
||||
"user": "held@example.com",
|
||||
"ts": ts,
|
||||
}
|
||||
)
|
||||
|
||||
def refuse(*_args: object) -> None:
|
||||
raise RuntimeError("the database is gone")
|
||||
|
||||
monkeypatch.setattr(collector, "_write", refuse)
|
||||
asyncio.run(collector.flush())
|
||||
monkeypatch.undo()
|
||||
asyncio.run(collector.flush())
|
||||
|
||||
audit = db.exec(
|
||||
select(EngineEvent).where(EngineEvent.actor == "held@example.com")
|
||||
).one()
|
||||
assert audit.detail == "held back"
|
||||
|
||||
|
||||
def test_a_node_id_wider_than_the_column_still_records(db: Session) -> None:
|
||||
collector = MetricsCollector(EventBus())
|
||||
ts = datetime.now(timezone.utc).replace(second=0, microsecond=0).timestamp()
|
||||
long_node = f"{FLOW}.{'w' * 400}"
|
||||
collector.handle(
|
||||
{
|
||||
"type": "node_executed",
|
||||
"flow": FLOW,
|
||||
"node": long_node,
|
||||
"duration_ms": 1.0,
|
||||
"ts": ts,
|
||||
}
|
||||
)
|
||||
asyncio.run(collector.flush())
|
||||
|
||||
bucket = db.exec(
|
||||
select(MetricBucket).where(MetricBucket.node == long_node[:255])
|
||||
).one()
|
||||
assert bucket.executions == 1
|
||||
|
||||
|
||||
def test_a_run_that_did_not_fail_reads_ok(db: Session) -> None:
|
||||
collector = MetricsCollector(EventBus())
|
||||
ts = time.time()
|
||||
|
||||
Reference in New Issue
Block a user