@neofinancial/chrono-mongo-datastore 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Neo Financial
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,25 @@
1
+ import { ClaimTaskInput, type Datastore, DeleteInput, DeleteOptions, type ScheduleInput, type Task, type TaskMappingBase } from '@neofinancial/chrono';
2
+ import { type ClientSession, type Db, type WithId } from 'mongodb';
3
+ export type ChronoMongoDatastoreConfig = {
4
+ completedDocumentTTL?: number;
5
+ collectionName: string;
6
+ };
7
+ export type MongoDatastoreOptions = {
8
+ session?: ClientSession;
9
+ };
10
+ export type TaskDocument<TaskKind, TaskData> = WithId<Omit<Task<TaskKind, TaskData>, 'id'>>;
11
+ export declare class ChronoMongoDatastore<TaskMapping extends TaskMappingBase> implements Datastore<TaskMapping, MongoDatastoreOptions> {
12
+ private config;
13
+ private database;
14
+ private constructor();
15
+ static create<TaskMapping extends TaskMappingBase>(database: Db, config?: Partial<ChronoMongoDatastoreConfig>): Promise<ChronoMongoDatastore<TaskMapping>>;
16
+ schedule<TaskKind extends keyof TaskMapping>(input: ScheduleInput<TaskKind, TaskMapping[TaskKind], MongoDatastoreOptions>): Promise<Task<TaskKind, TaskMapping[TaskKind]>>;
17
+ delete<TaskKind extends Extract<keyof TaskMapping, string>>(key: DeleteInput<TaskKind>, options?: DeleteOptions): Promise<Task<TaskKind, TaskMapping[TaskKind]> | undefined>;
18
+ claim<TaskKind extends Extract<keyof TaskMapping, string>>(input: ClaimTaskInput<TaskKind>): Promise<Task<TaskKind, TaskMapping[TaskKind]> | undefined>;
19
+ unclaim<TaskKind extends keyof TaskMapping>(taskId: string, nextScheduledAt: Date): Promise<Task<TaskKind, TaskMapping[TaskKind]>>;
20
+ complete<TaskKind extends keyof TaskMapping>(taskId: string): Promise<Task<TaskKind, TaskMapping[TaskKind]>>;
21
+ fail<TaskKind extends keyof TaskMapping>(taskId: string): Promise<Task<TaskKind, TaskMapping[TaskKind]>>;
22
+ private updateOrThrow;
23
+ private collection;
24
+ private toObject;
25
+ }
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ChronoMongoDatastore = void 0;
4
+ const chrono_1 = require("@neofinancial/chrono");
5
+ const mongodb_1 = require("mongodb");
6
+ const mongo_indexes_1 = require("./mongo-indexes");
7
+ const DEFAULT_COLLECTION_NAME = 'chrono-tasks';
8
+ class ChronoMongoDatastore {
9
+ config;
10
+ database;
11
+ constructor(database, config) {
12
+ this.database = database;
13
+ this.config = {
14
+ completedDocumentTTL: config?.completedDocumentTTL,
15
+ collectionName: config?.collectionName || DEFAULT_COLLECTION_NAME,
16
+ };
17
+ }
18
+ static async create(database, config) {
19
+ const datastore = new ChronoMongoDatastore(database, config);
20
+ await (0, mongo_indexes_1.ensureIndexes)(datastore.database.collection(datastore.config.collectionName), {
21
+ completedDocumentTTL: datastore.config.completedDocumentTTL,
22
+ });
23
+ return datastore;
24
+ }
25
+ async schedule(input) {
26
+ const createInput = {
27
+ kind: input.kind,
28
+ status: chrono_1.TaskStatus.PENDING,
29
+ data: input.data,
30
+ priority: input.priority,
31
+ idempotencyKey: input.idempotencyKey,
32
+ originalScheduleDate: input.when,
33
+ scheduledAt: input.when,
34
+ retryCount: 0,
35
+ };
36
+ try {
37
+ const results = await this.database.collection(this.config.collectionName).insertOne(createInput, {
38
+ ...(input?.datastoreOptions?.session ? { session: input.datastoreOptions.session } : undefined),
39
+ ignoreUndefined: true,
40
+ });
41
+ if (results.acknowledged) {
42
+ return this.toObject({ _id: results.insertedId, ...createInput });
43
+ }
44
+ }
45
+ catch (error) {
46
+ if (input.idempotencyKey &&
47
+ error instanceof Error &&
48
+ 'code' in error &&
49
+ (error.code === 11000 || error.code === 11001)) {
50
+ const existingTask = await this.collection().findOne({
51
+ idempotencyKey: input.idempotencyKey,
52
+ }, {
53
+ hint: mongo_indexes_1.IndexNames.IDEMPOTENCY_KEY_INDEX,
54
+ ...(input.datastoreOptions?.session ? { session: input.datastoreOptions.session } : undefined),
55
+ });
56
+ if (existingTask) {
57
+ return this.toObject(existingTask);
58
+ }
59
+ throw new Error(`Failed to find existing task with idempotency key ${input.idempotencyKey} despite unique index error`);
60
+ }
61
+ throw error;
62
+ }
63
+ throw new Error(`Failed to insert ${String(input.kind)} document`);
64
+ }
65
+ async delete(key, options) {
66
+ const filter = typeof key === 'string' ? { _id: new mongodb_1.ObjectId(key) } : { kind: key.kind, idempotencyKey: key.idempotencyKey };
67
+ const task = await this.collection().findOneAndDelete({
68
+ ...filter,
69
+ ...(options?.force ? {} : { status: chrono_1.TaskStatus.PENDING }),
70
+ });
71
+ if (!task) {
72
+ if (options?.force) {
73
+ return;
74
+ }
75
+ const description = typeof key === 'string'
76
+ ? `with id ${key}`
77
+ : `with kind ${String(key.kind)} and idempotencyKey ${key.idempotencyKey}`;
78
+ throw new Error(`Task ${description} can not be deleted as it may not exist or it's not in PENDING status.`);
79
+ }
80
+ return this.toObject(task);
81
+ }
82
+ async claim(input) {
83
+ const now = new Date();
84
+ const task = await this.collection().findOneAndUpdate({
85
+ kind: input.kind,
86
+ scheduledAt: { $lte: now },
87
+ $or: [
88
+ { status: chrono_1.TaskStatus.PENDING },
89
+ {
90
+ status: chrono_1.TaskStatus.CLAIMED,
91
+ claimedAt: {
92
+ $lte: new Date(now.getTime() - input.claimStaleTimeoutMs),
93
+ },
94
+ },
95
+ ],
96
+ }, { $set: { status: chrono_1.TaskStatus.CLAIMED, claimedAt: now } }, {
97
+ sort: { priority: -1, scheduledAt: 1 },
98
+ // hint: IndexNames.CLAIM_DOCUMENT_INDEX as unknown as Document,
99
+ returnDocument: 'after',
100
+ });
101
+ return task ? this.toObject(task) : undefined;
102
+ }
103
+ async unclaim(taskId, nextScheduledAt) {
104
+ const taskDocument = await this.updateOrThrow(taskId, {
105
+ $set: {
106
+ status: chrono_1.TaskStatus.PENDING,
107
+ scheduledAt: nextScheduledAt,
108
+ },
109
+ $inc: {
110
+ retryCount: 1,
111
+ },
112
+ });
113
+ return this.toObject(taskDocument);
114
+ }
115
+ async complete(taskId) {
116
+ const now = new Date();
117
+ const task = await this.updateOrThrow(taskId, {
118
+ $set: {
119
+ status: chrono_1.TaskStatus.COMPLETED,
120
+ completedAt: now,
121
+ lastExecutedAt: now,
122
+ },
123
+ });
124
+ return this.toObject(task);
125
+ }
126
+ async fail(taskId) {
127
+ const now = new Date();
128
+ const task = await this.updateOrThrow(taskId, {
129
+ $set: {
130
+ status: chrono_1.TaskStatus.FAILED,
131
+ lastExecutedAt: now,
132
+ },
133
+ });
134
+ return this.toObject(task);
135
+ }
136
+ async updateOrThrow(taskId, update) {
137
+ const document = await this.collection().findOneAndUpdate({ _id: new mongodb_1.ObjectId(taskId) }, update, {
138
+ returnDocument: 'after',
139
+ });
140
+ if (!document) {
141
+ throw new Error(`Task with ID ${taskId} not found`);
142
+ }
143
+ return document;
144
+ }
145
+ collection() {
146
+ return this.database.collection(this.config.collectionName);
147
+ }
148
+ toObject(document) {
149
+ return {
150
+ id: document._id.toHexString(),
151
+ data: document.data,
152
+ kind: document.kind,
153
+ status: document.status,
154
+ priority: document.priority ?? undefined,
155
+ idempotencyKey: document.idempotencyKey ?? undefined,
156
+ originalScheduleDate: document.originalScheduleDate,
157
+ scheduledAt: document.scheduledAt,
158
+ claimedAt: document.claimedAt ?? undefined,
159
+ completedAt: document.completedAt ?? undefined,
160
+ retryCount: document.retryCount,
161
+ };
162
+ }
163
+ }
164
+ exports.ChronoMongoDatastore = ChronoMongoDatastore;
165
+ //# sourceMappingURL=chrono-mongo-datastore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chrono-mongo-datastore.js","sourceRoot":"","sources":["../src/chrono-mongo-datastore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export { ChronoMongoDatastore, type MongoDatastoreOptions } from './chrono-mongo-datastore';
package/build/index.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ChronoMongoDatastore = void 0;
4
+ var chrono_mongo_datastore_1 = require("./chrono-mongo-datastore");
5
+ Object.defineProperty(exports, "ChronoMongoDatastore", { enumerable: true, get: function () { return chrono_mongo_datastore_1.ChronoMongoDatastore; } });
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,mEAA4F;AAAnF,8HAAA,oBAAoB,OAAA"}
@@ -0,0 +1 @@
1
+ export {};
package/build/main.js ADDED
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const chrono_core_1 = require("@neofinancial/chrono-core");
4
+ const mongo_task_1 = require("./mongo-task");
5
+ async function main() {
6
+ const task = new mongo_task_1.MongoTask();
7
+ const scheduler = new chrono_core_1.Scheduler();
8
+ await scheduler.schedule(task);
9
+ await scheduler.run();
10
+ console.log('Successfully ran MongoTask!');
11
+ }
12
+ main().catch(console.error);
13
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;AAAA,2DAAsD;AAEtD,6CAAyC;AAEzC,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,IAAI,sBAAS,EAAE,CAAC;IAC7B,MAAM,SAAS,GAAG,IAAI,uBAAS,EAAE,CAAC;IAElC,MAAM,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,SAAS,CAAC,GAAG,EAAE,CAAC;IAEtB,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;AAC7C,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { Collection } from 'mongodb';
2
+ export declare const DEFAULT_COMPLETED_DOCUMENT_TTL: number;
3
+ export declare const IndexNames: {
4
+ COMPLETED_DOCUMENT_TTL_INDEX: string;
5
+ CLAIM_DOCUMENT_INDEX: string;
6
+ IDEMPOTENCY_KEY_INDEX: string;
7
+ };
8
+ export type IndexDefinitionOptions = {
9
+ completedDocumentTTL?: number;
10
+ };
11
+ export declare function ensureIndexes(collection: Collection, options: IndexDefinitionOptions): Promise<void>;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.IndexNames = exports.DEFAULT_COMPLETED_DOCUMENT_TTL = void 0;
4
+ exports.ensureIndexes = ensureIndexes;
5
+ const chrono_1 = require("@neofinancial/chrono");
6
+ exports.DEFAULT_COMPLETED_DOCUMENT_TTL = 60 * 60 * 24 * 30; // 30 days
7
+ exports.IndexNames = {
8
+ COMPLETED_DOCUMENT_TTL_INDEX: 'chrono-completed-document-ttl-index',
9
+ CLAIM_DOCUMENT_INDEX: 'chrono-claim-document-index',
10
+ IDEMPOTENCY_KEY_INDEX: 'chrono-idempotency-key-index',
11
+ };
12
+ async function ensureIndexes(collection, options) {
13
+ await collection.createIndex({ completedAt: -1 }, {
14
+ partialFilterExpression: {
15
+ completedAt: { $exists: true },
16
+ status: { $eq: chrono_1.TaskStatus.COMPLETED },
17
+ },
18
+ expireAfterSeconds: options.completedDocumentTTL || exports.DEFAULT_COMPLETED_DOCUMENT_TTL,
19
+ name: exports.IndexNames.COMPLETED_DOCUMENT_TTL_INDEX,
20
+ });
21
+ await collection.createIndex({ kind: 1, status: 1, scheduledAt: 1, priority: -1, claimedAt: 1 }, { name: exports.IndexNames.CLAIM_DOCUMENT_INDEX });
22
+ await collection.createIndex({ idempotencyKey: 1 }, { name: exports.IndexNames.IDEMPOTENCY_KEY_INDEX, unique: true, sparse: true });
23
+ }
24
+ //# sourceMappingURL=mongo-indexes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mongo-indexes.js","sourceRoot":"","sources":["../src/mongo-indexes.ts"],"names":[],"mappings":";;;AAeA,sCAsBC;AArCD,iDAAkD;AAGrC,QAAA,8BAA8B,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,UAAU;AAE9D,QAAA,UAAU,GAAG;IACxB,4BAA4B,EAAE,qCAAqC;IACnE,oBAAoB,EAAE,6BAA6B;IACnD,qBAAqB,EAAE,8BAA8B;CACtD,CAAC;AAMK,KAAK,UAAU,aAAa,CAAC,UAAsB,EAAE,OAA+B;IACzF,MAAM,UAAU,CAAC,WAAW,CAC1B,EAAE,WAAW,EAAE,CAAC,CAAC,EAAE,EACnB;QACE,uBAAuB,EAAE;YACvB,WAAW,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;YAC9B,MAAM,EAAE,EAAE,GAAG,EAAE,mBAAU,CAAC,SAAS,EAAE;SACtC;QACD,kBAAkB,EAAE,OAAO,CAAC,oBAAoB,IAAI,sCAA8B;QAClF,IAAI,EAAE,kBAAU,CAAC,4BAA4B;KAC9C,CACF,CAAC;IAEF,MAAM,UAAU,CAAC,WAAW,CAC1B,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,EAClE,EAAE,IAAI,EAAE,kBAAU,CAAC,oBAAoB,EAAE,CAC1C,CAAC;IAEF,MAAM,UAAU,CAAC,WAAW,CAC1B,EAAE,cAAc,EAAE,CAAC,EAAE,EACrB,EAAE,IAAI,EAAE,kBAAU,CAAC,qBAAqB,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CACvE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Task } from '@neofinancial/chrono-core';
2
+ export declare class MongoTask implements Task<boolean> {
3
+ run(): Promise<boolean>;
4
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MongoTask = void 0;
4
+ class MongoTask {
5
+ async run() {
6
+ console.log('Running MongoTask');
7
+ return true;
8
+ }
9
+ }
10
+ exports.MongoTask = MongoTask;
11
+ //# sourceMappingURL=mongo-task.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mongo-task.js","sourceRoot":"","sources":["../src/mongo-task.ts"],"names":[],"mappings":";;;AAEA,MAAa,SAAS;IACb,KAAK,CAAC,GAAG;QACd,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QAEjC,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAND,8BAMC"}
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@neofinancial/chrono-mongo-datastore",
3
+ "version": "0.1.0",
4
+ "description": "",
5
+ "private": false,
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "main": "build/index.js",
10
+ "types": "build/index.d.ts",
11
+ "keywords": [],
12
+ "author": "Neo Financial Engineering <engineering@neofinancial.com>",
13
+ "license": "MIT",
14
+ "files": [
15
+ "build/**"
16
+ ],
17
+ "devDependencies": {
18
+ "mongodb": "^6.15",
19
+ "mongodb-memory-server": "^10.1.4",
20
+ "@neofinancial/chrono": "0.1.0"
21
+ },
22
+ "peerDependencies": {
23
+ "mongodb": "^6.15",
24
+ "@neofinancial/chrono": "0.1.0"
25
+ },
26
+ "scripts": {
27
+ "clean": "rimraf ./build",
28
+ "build": "tsc",
29
+ "typecheck": "tsc -p ./tsconfig.json --noEmit",
30
+ "test": "NODE_ENV=test TZ=UTC vitest run"
31
+ }
32
+ }