Transactions and logging¶
Operation lifecycle¶
Every add_file() or add_artifact() call runs inside a unit of work.
The unit of work tracks rollback actions so that a failed operation leaves the
catalog in a consistent state.
The typical lifecycle is:
Hooks fire in order (
before_validate_metadata,resolve_artifact_locator, …).Any file write happens.
The record is written to the database.
Post-write hooks fire (
after_record_write,before_commit,after_commit).
If any step raises an exception, registered rollback actions run in reverse order to undo any partial writes.
Audit events¶
Each catalog writes structured audit events to
<catalog-root>/.ogcat/logs/events.jsonl. The log is append-only during
normal operation and is intended for maintainers who need to answer which
operation ran, which user ran it, which record was touched, and where a failure
occurred.
Add operations emit lifecycle events for operation start, validation, storage
or record writes, commit, failure, and rollback. Delete and restore operations
emit the same operation-start, lifecycle, commit, failure, and rollback events.
Purge operations additionally emit one purge_artifact event for each
managed artifact removed or skipped, then hard-delete the record after artifact
cleanup succeeds. If one artifact removal fails, purge continues with later
artifacts, audits the failures, retains the tombstoned record with incomplete
purge metadata, and reports failure to the caller. Events include an
operation_id; CLI operation failures
include that id in the user-facing error message when available:
ogcat logs --catalog ./catalog --operation OPERATION_ID --json
ogcat logs --catalog ./catalog --user alice --level error
Audit details intentionally avoid recording file contents, in-memory
OperationSource.payload values, or full user metadata payloads. Metadata key
names and operation context are logged for diagnostics, and sensitive-looking
keys such as tokens, passwords, credentials, API keys, and private keys are
redacted when values are included in audit details.
Rollback¶
Rollback is best-effort. Each rollback action is tried in turn; if one fails, the remaining actions still run and the original error is preserved.
Catalog.delete() and Catalog.restore() update record lifecycle state
through the same unit-of-work rollback model used by metadata updates, so an
uncommitted caller-owned transaction restores the previous record state.
Catalog.purge() is permanent and best-effort: it removes only managed
catalog-local path-backed artifacts through storage adapters, audits skipped
external or user-owned locators, and hard-deletes the repository record last
only when cleanup succeeds. Partial purge failures cannot restore artifacts
that were already removed, so ogcat commits an updated tombstone describing the
incomplete attempt before raising the error.
You can register rollback actions from within a hook:
class MyHook:
def before_record_write(self, context):
path = write_something(context)
context.rollback(
lambda: path.unlink(missing_ok=True),
description=f"remove {path}",
)
Operation state¶
OperationState records the outcome of work tracked by the internal
UnitOfWork. add_file() and add_artifact() return a CatalogRecord;
they do not expose the operation context or final unit-of-work state. Callers
only inspect OperationState directly when they manage a transaction
themselves, for example by passing a caller-owned transaction into
add_artifact().
Using UnitOfWork directly¶
Most callers never need UnitOfWork directly. It is used internally by the
catalog and exposed for advanced use cases such as building a custom catalog
method that must participate in the same rollback lifecycle.
from ogcat.transactions import UnitOfWork
with UnitOfWork(catalog.repository) as uow:
uow.register_rollback(
lambda: cleanup(),
description="cleanup on failure",
)
do_work()
uow.commit()
# If commit is not called, the context manager rolls back on exit.