@x12i/countex-pipelines
v1.0.1
Published
Generic pre-aggregated processing counters for records moving through pipelines. Mongo source of truth, pluggable hot layer (in-process memory or Redis).
Maintainers
Readme
@x12i/countex-pipelines
Generic pre-aggregated processing counters for records moving through pipelines.
Countex-pipelines tracks status transitions (in_progress → done | failed) and serves rollups by subject, pipeline, and dimension — sub-second when the hot layer is warm, with no source-document scans at query time.
Package policy: Generic only. No host-product types, client names, or embedded scan logic. The host supplies historical replay via CountexRebuildSource when needed.
Default deployment: single machine, single process
The simplest and recommended starting config needs only MongoDB — no Redis required.
export MONGO_URI="mongodb://127.0.0.1:27017"
# REDIS_URL is optional — omit it for single-machine modeimport { createCountexFromEnv } from "@x12i/countex-pipelines";
const client = await createCountexFromEnv();
await client.initialize({ tenantId: "tenant-1", fromCounterStore: true });
await client.ingest({
tenantId: "tenant-1",
subject: "entities",
recordId: "rec-42",
pipelineId: "enrich",
status: "done",
occurredAt: new Date().toISOString(),
});
const rollup = await client.rollup({ tenantId: "tenant-1" });
console.log(rollup.bySubject, rollup.byPipeline);
await client.close();When REDIS_URL is absent, countex-pipelines uses an in-process MemoryHotStore. Mongo remains the source of truth; on restart the hot layer is empty and is re-warmed from Mongo automatically on initialize or first query. Do not run multiple processes with MemoryHotStore — use Redis for multi-server.
| Config | Hot layer | When to use |
|--------|-----------|-------------|
| MONGO_URI only | In-process memory | One machine, one process (default) |
| MONGO_URI + REDIS_URL | Shared Redis | Multiple servers, same counters |
| COUNTEX_READ_THROUGH=1 | None (read Mongo) | Minimal infra, low volume |
Three consumption surfaces (choose one)
1. Primitives (library-first)
Import pure functions and wire storage yourself:
import {
classifyRecord,
classifyPipeline,
buildDedupKey,
MemoryHotStore,
MongoDurableStore,
PipelinesEngine,
} from "@x12i/countex-pipelines";
// or: import from "@x12i/countex-pipelines/primitives"2. Embedded facade (in-process)
import { createCountexFromEnv } from "@x12i/countex-pipelines";
// or: import from "@x12i/countex-pipelines/client"3. HTTP API (optional separate package)
Run as a standalone service for remote or non-Node consumers:
npm install @x12i/countex-pipelines-server
MONGO_URI=... countex-pipelines-serverSee @x12i/countex-pipelines-server.
Ingest is write-through to Mongo — HTTP 200 means durably recorded.
Counter model
| Field | Role |
|-------|------|
| tenantId | Isolation scope |
| subject | Host-defined subject type |
| recordId | Item being processed |
| pipelineId | Host-defined processor / workflow id |
| dimensions | Optional tags for rollup axes |
| Metric | succeeded | pending | failed | running (derived) |
Classification (per record)
| Bucket | Rule |
|--------|------|
| succeeded | At least one pipeline done, and no pipeline failed |
| failed | At least one pipeline failed (wins over done) |
| pending | No terminal status yet |
| running | Per-pipeline: latest status is in_progress |
Starting from the middle
- Redis/memory empty, Mongo has counters →
initialize({ tenantId, fromCounterStore: true })reloads and warms the hot layer. - Counters never existed, host has history → implement
CountexRebuildSource.scan()and callinitialize({ tenantId, fromSource })(in-process only). - Process restart → same as (1); Mongo is source of truth.
Install
npm install @x12i/countex-pipelines mongodb
# optional for multi-server:
npm install ioredisNode 18+.
Docs
License
MIT
