dizzy.engine.sqla¶
dizzy.engine.sqla
¶
SQLAlchemy conveniences for hosts whose read models are a SQLite cache.
Optional, and deliberately kept out of the engine: :mod:dizzy.engine.loop
and :mod:dizzy.engine.rebuild touch read models only through the runners a
wiring registers, so DIZZY's runtime carries no ORM. This module is for the
common case rather than the required one, and lives behind the sqla extra.
What it provides is one idea: the read model is a disposable cache, and the stream is the truth, so schema drift is not a migration problem. A model that gains a column does not need an ALTER — it needs a refold. That makes one mechanism handle any schema change, and exercises the recoverability path instead of routing around it.
Freshness is judged by a COMPLETION MARKER (a file holding the schema fingerprint, written only after a successful refold), never by inspecting tables: a crashed rebuild leaves every table present-but-empty, which table inspection happily calls current. A missing or stale marker keeps retriggering the rebuild until one finishes.
Concurrency: a server and every worker run :func:ensure_current at startup,
so a file lock serializes them and late arrivals re-check the marker under the
lock and find the work already done. The lock and marker sit next to the
engine's own database file, so a test on a tmp path never touches real data.
The lock uses fcntl and is therefore POSIX-only; on other platforms call
:func:refold_if_stale yourself under whatever mutual exclusion you have.
db_path(path=None)
¶
Read-model database path: argument > $DIZZY_DB_PATH > default.
Source code in dizzy/src/dizzy/engine/sqla.py
41 42 43 | |
make_engine(path=None)
¶
A SQLite engine tuned for N workers folding into one file.
WAL lets readers proceed under a writer, and busy_timeout queues
writers instead of raising "database is locked" — both of which the mp
shell needs and the st shell is indifferent to.
Source code in dizzy/src/dizzy/engine/sqla.py
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | |
schema_fingerprint(metadatas)
¶
Deterministic digest of every model table's column set.
Source code in dizzy/src/dizzy/engine/sqla.py
70 71 72 73 74 75 | |
marker_path(sqla_engine)
¶
Where the completion marker for this engine's database lives.
Source code in dizzy/src/dizzy/engine/sqla.py
88 89 90 | |
refold_if_stale(sqla_engine, metadatas, refold, report=sys.stderr)
¶
Refold the stream if the marker does not match the model schema.
refold receives a session and returns the number of events folded —
lambda session: rebuild(store, session, runners, metadatas) is the
usual choice. Returns that count, or None if the cache was already
current. Caller provides mutual exclusion; see :func:ensure_current.
Source code in dizzy/src/dizzy/engine/sqla.py
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | |
ensure_current(sqla_engine, metadatas, refold, report=sys.stderr)
¶
Create missing tables, then heal schema drift by REBUILD, not ALTER.
Safe to call from every process at startup: a file lock serializes them, and whoever loses re-checks the marker and returns immediately.
Source code in dizzy/src/dizzy/engine/sqla.py
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | |