@nwire/mongo
v0.15.1
Published
Nwire — MongoDB adapters for ActorStore + ProjectionStore. (actorName, key, tenant) compound PK; fireAtList denormalized for indexable timer-scheduler queries; ensureIndexes() idempotent.
Readme
@nwire/mongo
MongoDB-backed
ActorStore+ProjectionStore— the canonical production store.
What it does
Persists actor state and projection rows to MongoDB. Tenant-partitioned. Includes idempotent ensureIndexes() ({actorName, tenant}, {actorName, fireAtList} for the timer scheduler, {projectionName, tenant} for read paths). Tested via mongodb-memory-server so suites run without Docker.
Install
pnpm add @nwire/mongo mongodbQuick start
import { MongoClient } from "mongodb";
import { MongoActorStore, MongoProjectionStore } from "@nwire/mongo";
import { createApp } from "@nwire/forge";
const client = await MongoClient.connect(process.env.MONGODB_URL!);
const db = client.db("learnflow");
const actorStore = new MongoActorStore(db.collection("actors"));
const projectionStore = new MongoProjectionStore(db.collection("projections"));
await actorStore.ensureIndexes();
await projectionStore.ensureIndexes();
const app = createApp("learnflow", { modules, actorStore, projectionStore });API surface
MongoActorStore(collection, options?)— implementsActorStore;.ensureIndexes().MongoProjectionStore(collection)— implementsProjectionStore;.ensureIndexes().createMongoActorStore(db, { actorCollection?, lockCollection?, lockTtlMs?, lockPollMs?, lockAcquireTimeoutMs? })— convenience factory; defaults:actors,actor_locks,30000,25,30000.
Distributed locking (HA / multi-replica)
Single-process deployments are safe with the default options — the runtime's
in-memory lock chain serialises dispatches per actor key. For multi-replica
deployments, pass a lockCollection so the per-(actor, key, tenant) critical
section is serialised across processes:
const actorStore = new MongoActorStore(db.collection("actors"), {
lockCollection: db.collection("actor_locks"),
lockTtlMs: 30_000, // max hold time before a competitor may reclaim
});
await actorStore.ensureIndexes(); // creates a TTL index on actor_locks.expiresAtMechanism: findOneAndUpdate({ _id, $or: [{ expiresAt: { $lt: now } }, { owner }] }, ..., { upsert: true })
atomically claims the lock or waits. On release the doc is deleted; if the
holder crashes the TTL takes over (belt and braces — index reaps within ~1
minute, but a live competitor reclaims as soon as expiresAt passes).
When to use
Production workloads with stateful actors and read-model projections.
Within nwire-app
For developers using this package as part of the Nwire stack — register it via app.use(...) or it auto-wires when you compose createApp({ modules }).
import { createApp } from "@nwire/forge";
const app = createApp({
/* ...config... */
});
// Adapter/plugin wiring happens here when applicable.