# @exellix/jobs-db

> Mongo-backed job queue data tier: JobRunStore, atomic claim, indexes. The only package that imports mongodb.

Latest version **1.1.0** (published 2026-07-11) · exellix-license license · 0 weekly downloads

## Install

```sh
npm install @exellix/jobs-db
pnpm add @exellix/jobs-db
yarn add @exellix/jobs-db
bun add @exellix/jobs-db
```

## Health

**Score 70/100 (B)** — status: active.

Positive: has types; esm support; no vulnerabilities; recently updated; high maintenance score; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 1.1.0 |
| Published | 2026-07-11 |
| First published | 2026-06-22 |
| Weekly downloads | 0 |
| License | exellix-license |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Node | >=20 |
| Dependencies | 3 |
| Unpacked size | 213.1 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Maintainers | exellix |
| Keywords | exellix, jobs, mongodb, persistence |

## Links

- npm: https://www.npmjs.com/package/@exellix/jobs-db
- Repository: https://github.com/exellix/exellix-engine-mono-repo
- Homepage: https://github.com/exellix/exellix-engine-mono-repo#readme
- Issues: https://github.com/exellix/exellix-engine-mono-repo/issues
- npm.io page: https://npm.io/package/@exellix/jobs-db

## Dependencies (3)

- [mongodb](https://npm.io/package/mongodb.md) ^6.21.0
- [@x12i/memorix-mongo](https://npm.io/package/@x12i/memorix-mongo.md) ^1.32.0
- [@x12i/memorix-retrieval](https://npm.io/package/@x12i/memorix-retrieval.md) ^1.33.0

## Alternatives

- [angular-pipes](https://npm.io/package/angular-pipes.md) — 5.6K weekly downloads
- [@ng-web-apis/midi](https://npm.io/package/@ng-web-apis/midi.md) — 2.6K weekly downloads
- [happn-3](https://npm.io/package/happn-3.md) — 1.6K weekly downloads
- [@opensip-cli/lang-go](https://npm.io/package/@opensip-cli/lang-go.md) — 1.2K weekly downloads
- [mongoose-typescript](https://npm.io/package/mongoose-typescript.md) — 85 weekly downloads

## Recent versions

- 1.1.0 (latest) — 2026-07-11
- 1.0.10 — 2026-07-10
- 1.0.9 — 2026-07-07
- 1.0.8 — 2026-07-05
- 1.0.7 — 2026-06-30
- 1.0.6 — 2026-06-26
- 1.0.5 — 2026-06-24
- 1.0.4 — 2026-06-24
- 1.0.3 — 2026-06-23
- 1.0.2 — 2026-06-22
- 1.0.1 — 2026-06-22

## README

# @exellix/jobs-db

Mongo-backed **data tier** for the Exellix job queue. This is the **only** package that imports `mongodb`. It exposes a small `JobRunStore` interface plus a native-driver implementation whose `claim` is a single atomic `findOneAndUpdate`.

> A **JobRun** is one graph run on one input — the durable queue work-unit. It is distinct from a graph **task node** and from an **ai-task** (`@exellix/ai-tasks`). See [`temp/jobs/`](../temp/jobs/README.md) for the full design.

## Install

```bash
npm install @exellix/jobs-db
```

## Usage

```ts
import { createJobRunStore } from '@exellix/jobs-db';

const { store, close } = await createJobRunStore({
  mongoUri: process.env.MONGO_URI,   // or set MONGO_URI in the environment
  // runtimeDb: 'exellix-jobs',       // default
  // configDb:  'exellix',            // default
  // ensureIndexes: true,             // default
});

const run = await store.claim('worker-1');   // atomic claim, or null
await store.close();                          // via close()
```

For tests, use the in-memory implementation:

```ts
import { createMemoryJobRunStore } from '@exellix/jobs-db';
const store = createMemoryJobRunStore();
```

## `JobRunStore` interface

```ts
interface JobRunStore {
  insertMany(runs: JobRun[]): Promise<void>;
  update(id: string, patch: Partial<JobRun>): Promise<void>;
  updateMany(filter: JobRunFilter, patch: Partial<JobRun>): Promise<{ modifiedCount: number }>;

  claim(workerId: string, opts?: ClaimOpts): Promise<JobRun | null>;   // atomic

  get(id: string): Promise<JobRun | null>;
  find(filter: JobRunFilter): Promise<JobRun[]>;
  count(filter: JobRunFilter): Promise<number>;
  hasItem(jobDefId: string, itemId: string): Promise<boolean>;          // dedup

  decrementPendingDeps(id: string): Promise<JobRun | null>;             // atomic
  close(): Promise<void>;
}
```

## Collections

| Collection | DB | Purpose |
|------------|-----|---------|
| `job_runs` | runtime (`exellix-jobs`) | the work-unit; source of truth |
| `job_defs` | config (`exellix`) | one doc per `JobDef` |
| `graphs` | config (`exellix`) | graph authoring JSON / per-graph defaults |
| `jobs_app_settings` | runtime | singleton app settings (`maxConcurrentJobs`, admission interval) |
| `job_run_events` *(optional)* | runtime | thin append-only audit log |

### App settings (`jobs_app_settings`)

One document (`id: 'default'`) caps how many job runs are admitted app-wide:

| Field | Default | Role |
|-------|---------|------|
| `maxConcurrentJobs` | **10** | Max admitted runs (pending + running, claimable) |
| `queueAdmissionIntervalMs` | **15000** | How often held runs are promoted when capacity frees |

Edited via [jobs-ui → Settings](../jobs-ui/README.md) (dashboard) or `JobsAppSettingsStore.save()`. See [parallel execution](../jobs/README.md#parallel-execution-and-capacity) for sizing guidance.

## Job context sources (`ContextSource`)

Work definitions, on-demand runs, and sync graph execute can attach optional **context sources** — linked-object and same-object Memorix slices resolved before dispatch into `jobMemory.context`:

| Type | Shape | Role |
|------|-------|------|
| `LinkedObjectContextSource` | `kind: 'linked'`, join fields, optional `filter`, `mandatory` | Resolve related records (e.g. subnets inferences joined on `data.subnetIp`) |
| `SameObjectContextSource` | `kind: 'same-object'`, `contentTypes[]` | Load other content types from the same record id |

Exported types: `ContextSource`, `LinkedObjectContextSource`, `SameObjectContextSource`, `ContextFilter`, `ContextSourceQueryOptions` (from `context-sources.ts`). Resolution logic lives in `@exellix/jobs`; the dispatcher receives pre-resolved `jobMemory` only.

The `(jobDefId, itemId)` index (`by_job_item`) is intentionally **non-unique** — one item produces one job run per graph. Dedup is enforced by `hasItem` at enqueue time, not by a unique constraint.

## Why a separate package

`@x12i/xronox-store` has no atomic conditional update (`findOneAndUpdate`), which forced the old Execution Matrix into in-process `withClaimLock`. A durable cross-process queue needs structural atomicity, so the data tier uses the native `mongodb` driver and is kept out of the queue logic.

## Scripts

```bash
npm run build      # tsc → dist/
npm test           # unit + live (live runs only when MONGO_URI is set)
npm run test:live  # live Mongo integration tests only
```

Live tests read `MONGO_URI` from the environment, falling back to `../../graph-packages/graph-engine/.env`. Each run uses an isolated `exellix-jobs-live-*` database that is dropped on teardown.

## License

exellix-license

---
_Source: https://npm.io/package/@exellix/jobs-db · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
