Waher.Persistence.Database abstraction. The configured provider can be the files database, lightweight files database, an external provider, or a test provider; application code should not depend on one storage engine’s files.
Define a persisted model
CRUD
FilterAnd/FilterOr, and paging/sort arguments. Use bounded reads. FindFirstDeleteRest deliberately deletes duplicate matches and should only be used when uniqueness and cleanup are intended.
Consistency
The generic object API does not turn an arbitrary read-modify-write sequence into a cross-object transaction. Design with:- unique business identifiers and idempotent commands;
- explicit state transitions;
- optimistic conflict checks where competing writers are possible;
- persisted intent/outbox records before invoking external services;
- reconciliation jobs for interrupted work.
Waher.Runtime.Transactions only after understanding the participating resources and recovery behavior.
Persistent queues
DatabaseQueue/IPersistedQueue provide durable FIFO work, and the /Queues service exposes authorized HTTP access when installed. Use distinct queue names per contract and environment. A consumer should:
- dequeue a bounded batch with a timeout;
- validate and deserialize defensively;
- apply an idempotency key before side effects;
- record success or a retry/dead-letter decision;
- expose depth, age, throughput, and failures as counters/events.
Task.Run loop for work that must survive restart.
Structured event log
UseWaher.Events.Log for operational events. Levels range from debug and informational through notice, warning, error, critical, alert, and emergency. Include stable object/actor/facility/event identifiers and structured tags so operators and the Event Log MCP server can search them.