mongodash 2.0.0 → 2.1.1
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/README.md +107 -23
- package/dist/dashboard/index.html +40 -0
- package/dist/lib/playground/server.js +124 -0
- package/dist/lib/playground/server.js.map +1 -0
- package/dist/lib/src/ConcurrentRunner.js +141 -0
- package/dist/lib/src/ConcurrentRunner.js.map +1 -0
- package/dist/lib/{OnError.js → src/OnError.js} +2 -9
- package/dist/lib/src/OnError.js.map +1 -0
- package/dist/lib/{OnInfo.js → src/OnInfo.js} +5 -9
- package/dist/lib/src/OnInfo.js.map +1 -0
- package/dist/lib/{createContinuousLock.js → src/createContinuousLock.js} +4 -9
- package/dist/lib/src/createContinuousLock.js.map +1 -0
- package/dist/lib/{cronTasks.js → src/cronTasks.js} +128 -79
- package/dist/lib/src/cronTasks.js.map +1 -0
- package/dist/lib/{getCollection.js → src/getCollection.js} +1 -8
- package/dist/lib/src/getCollection.js.map +1 -0
- package/dist/lib/{getMongoClient.js → src/getMongoClient.js} +1 -8
- package/dist/lib/src/getMongoClient.js.map +1 -0
- package/dist/lib/src/globalsCollection.js +3 -0
- package/dist/lib/src/globalsCollection.js.map +1 -0
- package/dist/lib/src/index.js +94 -0
- package/dist/lib/src/index.js.map +1 -0
- package/dist/lib/src/initPromise.js +9 -0
- package/dist/lib/src/initPromise.js.map +1 -0
- package/dist/lib/src/mongoCompatibility.js +3 -0
- package/dist/lib/src/mongoCompatibility.js.map +1 -0
- package/dist/lib/src/parseInterval.js +53 -0
- package/dist/lib/src/parseInterval.js.map +1 -0
- package/dist/lib/src/prefixFilterKeys.js +62 -0
- package/dist/lib/src/prefixFilterKeys.js.map +1 -0
- package/dist/lib/src/processInBatches.js +39 -0
- package/dist/lib/src/processInBatches.js.map +1 -0
- package/dist/lib/src/reactiveTasks/LeaderElector.js +148 -0
- package/dist/lib/src/reactiveTasks/LeaderElector.js.map +1 -0
- package/dist/lib/src/reactiveTasks/MetricsCollector.js +403 -0
- package/dist/lib/src/reactiveTasks/MetricsCollector.js.map +1 -0
- package/dist/lib/src/reactiveTasks/ReactiveTaskManager.js +281 -0
- package/dist/lib/src/reactiveTasks/ReactiveTaskManager.js.map +1 -0
- package/dist/lib/src/reactiveTasks/ReactiveTaskOps.js +178 -0
- package/dist/lib/src/reactiveTasks/ReactiveTaskOps.js.map +1 -0
- package/dist/lib/src/reactiveTasks/ReactiveTaskPlanner.js +436 -0
- package/dist/lib/src/reactiveTasks/ReactiveTaskPlanner.js.map +1 -0
- package/dist/lib/src/reactiveTasks/ReactiveTaskReconciler.js +211 -0
- package/dist/lib/src/reactiveTasks/ReactiveTaskReconciler.js.map +1 -0
- package/dist/lib/src/reactiveTasks/ReactiveTaskRegistry.js +177 -0
- package/dist/lib/src/reactiveTasks/ReactiveTaskRegistry.js.map +1 -0
- package/dist/lib/src/reactiveTasks/ReactiveTaskRepository.js +348 -0
- package/dist/lib/src/reactiveTasks/ReactiveTaskRepository.js.map +1 -0
- package/dist/lib/src/reactiveTasks/ReactiveTaskRetryStrategy.js +146 -0
- package/dist/lib/src/reactiveTasks/ReactiveTaskRetryStrategy.js.map +1 -0
- package/dist/lib/src/reactiveTasks/ReactiveTaskTypes.js +27 -0
- package/dist/lib/src/reactiveTasks/ReactiveTaskTypes.js.map +1 -0
- package/dist/lib/src/reactiveTasks/ReactiveTaskWorker.js +179 -0
- package/dist/lib/src/reactiveTasks/ReactiveTaskWorker.js.map +1 -0
- package/dist/lib/src/reactiveTasks/compileWatchProjection.js +58 -0
- package/dist/lib/src/reactiveTasks/compileWatchProjection.js.map +1 -0
- package/dist/lib/src/reactiveTasks/index.js +291 -0
- package/dist/lib/src/reactiveTasks/index.js.map +1 -0
- package/dist/lib/src/reactiveTasks/queryToExpression.js +153 -0
- package/dist/lib/src/reactiveTasks/queryToExpression.js.map +1 -0
- package/dist/lib/src/reactiveTasks/validateTaskFilter.js +81 -0
- package/dist/lib/src/reactiveTasks/validateTaskFilter.js.map +1 -0
- package/dist/lib/src/task-management/OperationalTaskController.js +155 -0
- package/dist/lib/src/task-management/OperationalTaskController.js.map +1 -0
- package/dist/lib/src/task-management/index.js +20 -0
- package/dist/lib/src/task-management/index.js.map +1 -0
- package/dist/lib/src/task-management/serveDashboard.js +142 -0
- package/dist/lib/src/task-management/serveDashboard.js.map +1 -0
- package/dist/lib/src/task-management/types.js +3 -0
- package/dist/lib/src/task-management/types.js.map +1 -0
- package/dist/lib/{withLock.js → src/withLock.js} +2 -10
- package/dist/lib/src/withLock.js.map +1 -0
- package/dist/lib/{withTransaction.js → src/withTransaction.js} +3 -10
- package/dist/lib/src/withTransaction.js.map +1 -0
- package/dist/lib/tools/check-db-connection.js +21 -0
- package/dist/lib/tools/check-db-connection.js.map +1 -0
- package/dist/lib/tools/clean-testing-databases.js +5 -0
- package/dist/lib/tools/clean-testing-databases.js.map +1 -0
- package/dist/lib/tools/prepare-republish.js +20 -0
- package/dist/lib/tools/prepare-republish.js.map +1 -0
- package/dist/lib/tools/test-matrix-local.js +205 -0
- package/dist/lib/tools/test-matrix-local.js.map +1 -0
- package/dist/lib/tools/testingDatabase.js +48 -0
- package/dist/lib/tools/testingDatabase.js.map +1 -0
- package/dist/types/playground/server.d.ts +1 -0
- package/dist/types/src/ConcurrentRunner.d.ts +30 -0
- package/dist/types/{OnInfo.d.ts → src/OnInfo.d.ts} +1 -1
- package/dist/types/{cronTasks.d.ts → src/cronTasks.d.ts} +44 -1
- package/dist/types/src/globalsCollection.d.ts +4 -0
- package/dist/types/src/index.d.ts +28 -0
- package/dist/types/src/mongoCompatibility.d.ts +29 -0
- package/dist/types/src/parseInterval.d.ts +12 -0
- package/dist/types/src/prefixFilterKeys.d.ts +11 -0
- package/dist/types/src/processInBatches.d.ts +10 -0
- package/dist/types/src/reactiveTasks/LeaderElector.d.ts +42 -0
- package/dist/types/src/reactiveTasks/MetricsCollector.d.ts +73 -0
- package/dist/types/src/reactiveTasks/ReactiveTaskManager.d.ts +18 -0
- package/dist/types/src/reactiveTasks/ReactiveTaskOps.d.ts +17 -0
- package/dist/types/src/reactiveTasks/ReactiveTaskPlanner.d.ts +62 -0
- package/dist/types/src/reactiveTasks/ReactiveTaskReconciler.d.ts +29 -0
- package/dist/types/src/reactiveTasks/ReactiveTaskRegistry.d.ts +34 -0
- package/dist/types/src/reactiveTasks/ReactiveTaskRepository.d.ts +59 -0
- package/dist/types/src/reactiveTasks/ReactiveTaskRetryStrategy.d.ts +21 -0
- package/dist/types/src/reactiveTasks/ReactiveTaskTypes.d.ts +389 -0
- package/dist/types/src/reactiveTasks/ReactiveTaskWorker.d.ts +36 -0
- package/dist/types/src/reactiveTasks/compileWatchProjection.d.ts +12 -0
- package/dist/types/src/reactiveTasks/index.d.ts +82 -0
- package/dist/types/src/reactiveTasks/queryToExpression.d.ts +13 -0
- package/dist/types/src/reactiveTasks/validateTaskFilter.d.ts +10 -0
- package/dist/types/src/task-management/OperationalTaskController.d.ts +59 -0
- package/dist/types/src/task-management/index.d.ts +3 -0
- package/dist/types/src/task-management/serveDashboard.d.ts +12 -0
- package/dist/types/src/task-management/types.d.ts +95 -0
- package/dist/types/tools/check-db-connection.d.ts +2 -0
- package/dist/types/tools/clean-testing-databases.d.ts +1 -0
- package/dist/types/tools/prepare-republish.d.ts +2 -0
- package/dist/types/tools/test-matrix-local.d.ts +1 -0
- package/dist/types/tools/testingDatabase.d.ts +2 -0
- package/docs/.vitepress/cache/deps/_metadata.json +31 -0
- package/docs/.vitepress/cache/deps/chunk-LE5NDSFD.js +12824 -0
- package/docs/.vitepress/cache/deps/chunk-LE5NDSFD.js.map +7 -0
- package/docs/.vitepress/cache/deps/package.json +3 -0
- package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +4505 -0
- package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +7 -0
- package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +9731 -0
- package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +7 -0
- package/docs/.vitepress/cache/deps/vue.js +347 -0
- package/docs/.vitepress/cache/deps/vue.js.map +7 -0
- package/docs/.vitepress/config.mts +50 -0
- package/docs/.vitepress/theme/index.ts +4 -0
- package/docs/.vitepress/theme/style.css +21 -0
- package/docs/assets/dashboard.png +0 -0
- package/docs/cron-tasks.md +172 -0
- package/docs/dashboard.md +117 -0
- package/docs/getters.md +31 -0
- package/docs/getting-started.md +186 -0
- package/docs/index.md +32 -0
- package/docs/initialization.md +59 -0
- package/docs/process-in-batches.md +73 -0
- package/docs/public/logo.png +0 -0
- package/docs/reactive-tasks.md +913 -0
- package/docs/with-lock.md +45 -0
- package/docs/with-transaction.md +65 -0
- package/grafana/reactive_tasks.json +765 -0
- package/package.json +131 -116
- package/dist/lib/OnError.js.map +0 -1
- package/dist/lib/OnInfo.js.map +0 -1
- package/dist/lib/createContinuousLock.js.map +0 -1
- package/dist/lib/cronTasks.js.map +0 -1
- package/dist/lib/getCollection.js.map +0 -1
- package/dist/lib/getMongoClient.js.map +0 -1
- package/dist/lib/index.js +0 -64
- package/dist/lib/index.js.map +0 -1
- package/dist/lib/initPromise.js +0 -17
- package/dist/lib/initPromise.js.map +0 -1
- package/dist/lib/withLock.js.map +0 -1
- package/dist/lib/withTransaction.js.map +0 -1
- package/dist/types/index.d.ts +0 -17
- /package/dist/types/{OnError.d.ts → src/OnError.d.ts} +0 -0
- /package/dist/types/{createContinuousLock.d.ts → src/createContinuousLock.d.ts} +0 -0
- /package/dist/types/{getCollection.d.ts → src/getCollection.d.ts} +0 -0
- /package/dist/types/{getMongoClient.d.ts → src/getMongoClient.d.ts} +0 -0
- /package/dist/types/{initPromise.d.ts → src/initPromise.d.ts} +0 -0
- /package/dist/types/{withLock.d.ts → src/withLock.d.ts} +0 -0
- /package/dist/types/{withTransaction.d.ts → src/withTransaction.d.ts} +0 -0
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ReactiveTaskPlanner = void 0;
|
|
4
|
+
const stringify = require("fast-json-stable-stringify");
|
|
5
|
+
const _debug = require("debug");
|
|
6
|
+
const getMongoClient_1 = require("../getMongoClient");
|
|
7
|
+
const prefixFilterKeys_1 = require("../prefixFilterKeys");
|
|
8
|
+
const ReactiveTaskTypes_1 = require("./ReactiveTaskTypes");
|
|
9
|
+
const OnInfo_1 = require("../OnInfo");
|
|
10
|
+
const OnError_1 = require("../OnError");
|
|
11
|
+
const bson_1 = require("bson");
|
|
12
|
+
const ReactiveTaskOps_1 = require("./ReactiveTaskOps");
|
|
13
|
+
const ReactiveTaskReconciler_1 = require("./ReactiveTaskReconciler");
|
|
14
|
+
const debug = _debug('mongodash:reactiveTasks:planner');
|
|
15
|
+
/**
|
|
16
|
+
* Responsible for listening to MongoDB Change Stream events and planning tasks.
|
|
17
|
+
*
|
|
18
|
+
* Responsibilities:
|
|
19
|
+
* - Manages the lifecycle of the Change Stream (start, stop, error handling).
|
|
20
|
+
* - Batches Change Stream events to reduce database load.
|
|
21
|
+
* - Coordinates with `ReactiveTaskOps` to generate and execute task operations.
|
|
22
|
+
* - Coordinates with `ReactiveTaskReconciler` to handle reconciliation when the stream is interrupted or history is lost.
|
|
23
|
+
* - Handles critical errors like `ChangeStreamHistoryLost` (code 280) by triggering reconciliation.
|
|
24
|
+
*/
|
|
25
|
+
class ReactiveTaskPlanner {
|
|
26
|
+
get isStoppedTester() {
|
|
27
|
+
return () => this.changeStream === null;
|
|
28
|
+
}
|
|
29
|
+
constructor(globalsCollection, instanceId, registry, callbacks, internalOptions, onInfo = OnInfo_1.defaultOnInfo, onError = OnError_1.defaultOnError) {
|
|
30
|
+
this.globalsCollection = globalsCollection;
|
|
31
|
+
this.instanceId = instanceId;
|
|
32
|
+
this.registry = registry;
|
|
33
|
+
this.callbacks = callbacks;
|
|
34
|
+
this.internalOptions = internalOptions;
|
|
35
|
+
this.onInfo = onInfo;
|
|
36
|
+
this.onError = onError;
|
|
37
|
+
this.changeStream = null;
|
|
38
|
+
this.taskBatch = new Map();
|
|
39
|
+
this.taskBatchLastResumeToken = null;
|
|
40
|
+
this.batchFlushTimer = null;
|
|
41
|
+
this.isFlushing = false;
|
|
42
|
+
this.metaDocId = ReactiveTaskTypes_1.REACTIVE_TASK_META_DOC_ID;
|
|
43
|
+
this.lastClusterTime = null;
|
|
44
|
+
this.isStopping = false;
|
|
45
|
+
this.ops = new ReactiveTaskOps_1.ReactiveTaskOps(registry, callbacks.onTaskPlanned);
|
|
46
|
+
this.reconciler = new ReactiveTaskReconciler_1.ReactiveTaskReconciler(instanceId, globalsCollection, registry, this.ops, onInfo, internalOptions);
|
|
47
|
+
}
|
|
48
|
+
async start() {
|
|
49
|
+
this.onInfo({
|
|
50
|
+
message: `Reactive task planner started.`,
|
|
51
|
+
code: ReactiveTaskTypes_1.CODE_REACTIVE_TASK_PLANNER_STARTED,
|
|
52
|
+
});
|
|
53
|
+
// 1. Check for schema/logic evolution (Filter changes, Version upgrades)
|
|
54
|
+
await this.checkEvolutionStrategies();
|
|
55
|
+
// 2. Start stream first to ensure we don't miss events during reconciliation
|
|
56
|
+
// We capture the time AFTER starting to ensure overlap with the stream.
|
|
57
|
+
// This prevents a gap where events occurring between "now" and "stream start" would be missed.
|
|
58
|
+
await this.startChangeStream();
|
|
59
|
+
// Pass the current stream instance to reconcile. If stream fails/restarts, instance changes and reconcile aborts.
|
|
60
|
+
if (this.changeStream) {
|
|
61
|
+
await this.reconciler.reconcile(this.isStoppedTester);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async stop() {
|
|
65
|
+
await this.stopChangeStream();
|
|
66
|
+
this.onInfo({
|
|
67
|
+
message: `Reactive task planner stopped.`,
|
|
68
|
+
code: ReactiveTaskTypes_1.CODE_REACTIVE_TASK_PLANNER_STOPPED,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
async saveResumeToken(token, lastClusterTime) {
|
|
72
|
+
const setFields = { 'streamState.resumeToken': token };
|
|
73
|
+
if (lastClusterTime) {
|
|
74
|
+
setFields['streamState.lastClusterTime'] = lastClusterTime;
|
|
75
|
+
}
|
|
76
|
+
await this.globalsCollection.updateOne({ _id: this.metaDocId }, { $set: setFields }, { upsert: true });
|
|
77
|
+
}
|
|
78
|
+
get isEmpty() {
|
|
79
|
+
return this.taskBatch.size === 0 && !this.isFlushing;
|
|
80
|
+
}
|
|
81
|
+
async onHeartbeat() {
|
|
82
|
+
// Save resume token if stream is running and idle
|
|
83
|
+
if (this.changeStream && this.isEmpty) {
|
|
84
|
+
await this.saveResumeToken(this.changeStream.resumeToken, this.lastClusterTime ? new Date(this.lastClusterTime * 1000) : undefined);
|
|
85
|
+
}
|
|
86
|
+
// Periodic cleanup of orphaned tasks
|
|
87
|
+
await this.reconciler.performPeriodicCleanup(this.isStoppedTester);
|
|
88
|
+
}
|
|
89
|
+
async startChangeStream() {
|
|
90
|
+
if (this.changeStream) {
|
|
91
|
+
await this.stopChangeStream();
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
const streamOptions = {
|
|
95
|
+
resumeAfter: await this.getChangeStreamResumeToken(),
|
|
96
|
+
fullDocument: 'updateLookup',
|
|
97
|
+
};
|
|
98
|
+
if (!streamOptions.resumeAfter) {
|
|
99
|
+
// get current server time to guarantee we get any operation from the current time
|
|
100
|
+
// even if the watch operation took a time, since it is async and we don't have
|
|
101
|
+
// any guaranty at what point we start listening
|
|
102
|
+
const serverStatus = await (0, getMongoClient_1.getMongoClient)().db().command({ hello: 1 });
|
|
103
|
+
if (serverStatus && serverStatus.operationTime) {
|
|
104
|
+
this.onInfo({
|
|
105
|
+
message: `No token found. Starting from operationTime: ${serverStatus.operationTime}`,
|
|
106
|
+
code: ReactiveTaskTypes_1.CODE_REACTIVE_TASK_PLANNER_STARTED,
|
|
107
|
+
operationTime: serverStatus.operationTime,
|
|
108
|
+
});
|
|
109
|
+
streamOptions.startAtOperationTime = serverStatus.operationTime;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// Fallback pro standalone instance bez oplogu (méně časté v produkci)
|
|
113
|
+
this.onInfo({
|
|
114
|
+
message: `Could not fetch operationTime. Starting standard watch.`,
|
|
115
|
+
code: ReactiveTaskTypes_1.CODE_REACTIVE_TASK_PLANNER_STARTED,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const pipeline = this.getChangeStreamPipeline();
|
|
120
|
+
debug(`[Scheduler ${this.instanceId}] Change Stream Pipeline: `, JSON.stringify(pipeline, null, 2));
|
|
121
|
+
// Determine which database to watch
|
|
122
|
+
// We assume all monitored collections are in the same database for now.
|
|
123
|
+
const tasks = this.registry.getAllTasks();
|
|
124
|
+
let dbToWatch = (0, getMongoClient_1.getMongoClient)().db(); // Default
|
|
125
|
+
if (tasks.length > 0) {
|
|
126
|
+
const dbName = tasks[0].sourceCollection.dbName;
|
|
127
|
+
dbToWatch = (0, getMongoClient_1.getMongoClient)().db(dbName);
|
|
128
|
+
debug(`[ReactiveTaskPlanner] Watching database: ${dbName}`);
|
|
129
|
+
}
|
|
130
|
+
const stream = dbToWatch.watch(pipeline, streamOptions);
|
|
131
|
+
this.changeStream = stream;
|
|
132
|
+
stream.on('change', (change) => {
|
|
133
|
+
this.enqueueTaskChange(change);
|
|
134
|
+
});
|
|
135
|
+
stream.on('resumeTokenChanged', () => {
|
|
136
|
+
if (this.isEmpty) {
|
|
137
|
+
this.lastClusterTime = Date.now() / 1000;
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
stream.on('error', (error) => this.handleStreamError(error));
|
|
141
|
+
stream.on('close', () => {
|
|
142
|
+
this.onInfo({
|
|
143
|
+
message: `Change Stream closed.`,
|
|
144
|
+
code: ReactiveTaskTypes_1.CODE_REACTIVE_TASK_PLANNER_STOPPED,
|
|
145
|
+
});
|
|
146
|
+
if (!this.isStopping) {
|
|
147
|
+
this.callbacks.onStreamError();
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
this.onInfo({
|
|
153
|
+
message: `Failed to start Change Stream: ${error.message}`,
|
|
154
|
+
code: ReactiveTaskTypes_1.CODE_REACTIVE_TASK_PLANNER_STREAM_ERROR,
|
|
155
|
+
error: error.message,
|
|
156
|
+
});
|
|
157
|
+
this.callbacks.onStreamError();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async stopChangeStream() {
|
|
161
|
+
if (this.changeStream) {
|
|
162
|
+
this.isStopping = true;
|
|
163
|
+
debug(`[Scheduler ${this.instanceId}] Stopping Change Stream...`);
|
|
164
|
+
await this.changeStream.close();
|
|
165
|
+
this.changeStream = null;
|
|
166
|
+
this.isStopping = false;
|
|
167
|
+
}
|
|
168
|
+
await this.flushTaskBatch();
|
|
169
|
+
}
|
|
170
|
+
getChangeStreamPipeline() {
|
|
171
|
+
const collectionFilters = this.registry.getAllTasks().reduce((acc, taskDef) => {
|
|
172
|
+
const collectionName = taskDef.sourceCollection.collectionName;
|
|
173
|
+
if (!acc.has(collectionName)) {
|
|
174
|
+
acc.set(collectionName, { 'ns.coll': collectionName, $or: [] });
|
|
175
|
+
}
|
|
176
|
+
acc.get(collectionName).$or.push((0, prefixFilterKeys_1.prefixFilterKeys)({ $expr: taskDef.filter || {} }, 'fullDocument'));
|
|
177
|
+
return acc;
|
|
178
|
+
}, new Map());
|
|
179
|
+
const pipeline = [
|
|
180
|
+
{
|
|
181
|
+
$match: {
|
|
182
|
+
operationType: { $in: ['insert', 'update', 'replace', 'delete'] },
|
|
183
|
+
$or: Array.from(collectionFilters.values()),
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
$project: {
|
|
188
|
+
_id: 1,
|
|
189
|
+
operationType: 1,
|
|
190
|
+
ns: 1,
|
|
191
|
+
documentKey: 1,
|
|
192
|
+
clusterTime: 1,
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
];
|
|
196
|
+
return pipeline;
|
|
197
|
+
}
|
|
198
|
+
async getChangeStreamResumeToken() {
|
|
199
|
+
var _a;
|
|
200
|
+
const state = (await this.globalsCollection.findOne({
|
|
201
|
+
_id: this.metaDocId,
|
|
202
|
+
}));
|
|
203
|
+
debug(`[DEBUG] getChangeStreamResumeToken loaded state (${this.metaDocId}): `, JSON.stringify(state, null, 2));
|
|
204
|
+
const token = (_a = state === null || state === void 0 ? void 0 : state.streamState) === null || _a === void 0 ? void 0 : _a.resumeToken;
|
|
205
|
+
debug(`[DEBUG] Extracted token: `, token);
|
|
206
|
+
return token !== null && token !== void 0 ? token : undefined;
|
|
207
|
+
}
|
|
208
|
+
async enqueueTaskChange(change) {
|
|
209
|
+
debug(`[Scheduler ${this.instanceId}] Change detected: `, change._id);
|
|
210
|
+
if (change.clusterTime) {
|
|
211
|
+
// clusterTime is a BSON Timestamp.
|
|
212
|
+
// .getHighBits() returns the seconds since epoch.
|
|
213
|
+
this.lastClusterTime = change.clusterTime.getHighBits();
|
|
214
|
+
}
|
|
215
|
+
const docId = bson_1.EJSON.stringify(change.documentKey._id, { relaxed: false });
|
|
216
|
+
this.taskBatch.set(docId, change);
|
|
217
|
+
this.taskBatchLastResumeToken = change._id;
|
|
218
|
+
if (this.taskBatch.size >= this.internalOptions.batchSize) {
|
|
219
|
+
if (this.batchFlushTimer) {
|
|
220
|
+
clearTimeout(this.batchFlushTimer);
|
|
221
|
+
this.batchFlushTimer = null;
|
|
222
|
+
}
|
|
223
|
+
await this.flushTaskBatch();
|
|
224
|
+
}
|
|
225
|
+
else if (!this.batchFlushTimer) {
|
|
226
|
+
this.batchFlushTimer = setTimeout(() => this.flushTaskBatch(), this.internalOptions.batchIntervalMs);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
async flushTaskBatch() {
|
|
230
|
+
if (this.batchFlushTimer) {
|
|
231
|
+
clearTimeout(this.batchFlushTimer);
|
|
232
|
+
this.batchFlushTimer = null;
|
|
233
|
+
}
|
|
234
|
+
if (this.taskBatch.size === 0) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const events = Array.from(this.taskBatch.values());
|
|
238
|
+
this.taskBatch.clear();
|
|
239
|
+
const lastToken = this.taskBatchLastResumeToken;
|
|
240
|
+
const lastClusterTime = this.lastClusterTime ? new Date(this.lastClusterTime * 1000) : undefined; // Capture time associated with this batch (approx)
|
|
241
|
+
this.isFlushing = true;
|
|
242
|
+
try {
|
|
243
|
+
const { idsByCollection, deletedIdsByTask } = this.groupEventsByCollection(events);
|
|
244
|
+
await this.processDeletions(deletedIdsByTask);
|
|
245
|
+
await this.executeUpsertOperations(idsByCollection);
|
|
246
|
+
if (lastToken) {
|
|
247
|
+
await this.saveResumeToken(lastToken, lastClusterTime);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
this.onError(error);
|
|
252
|
+
// We lost the batch, but we can't easily retry without complicating logic.
|
|
253
|
+
// The stream continues.
|
|
254
|
+
}
|
|
255
|
+
finally {
|
|
256
|
+
this.isFlushing = false;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
groupEventsByCollection(events) {
|
|
260
|
+
const idsByCollection = new Map();
|
|
261
|
+
// Map<TaskName, Set<SourceId>>
|
|
262
|
+
const deletedIdsByTask = new Map();
|
|
263
|
+
for (const event of events) {
|
|
264
|
+
if (!event.ns || !event.ns.coll)
|
|
265
|
+
continue;
|
|
266
|
+
const collectionName = event.ns.coll;
|
|
267
|
+
if (event.operationType === 'delete') {
|
|
268
|
+
const docId = event.documentKey._id;
|
|
269
|
+
const entry = this.registry.getEntry(collectionName);
|
|
270
|
+
if (entry) {
|
|
271
|
+
for (const taskDef of entry.tasks.values()) {
|
|
272
|
+
let docIds = deletedIdsByTask.get(taskDef.task);
|
|
273
|
+
if (!docIds) {
|
|
274
|
+
docIds = new Set();
|
|
275
|
+
deletedIdsByTask.set(taskDef.task, docIds);
|
|
276
|
+
}
|
|
277
|
+
docIds.add(docId);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
// insert, update, replace
|
|
283
|
+
if (!idsByCollection.has(collectionName)) {
|
|
284
|
+
idsByCollection.set(collectionName, new Set());
|
|
285
|
+
}
|
|
286
|
+
idsByCollection.get(collectionName).add(event.documentKey._id);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
return { idsByCollection, deletedIdsByTask };
|
|
290
|
+
}
|
|
291
|
+
async processDeletions(deletedIdsByTask) {
|
|
292
|
+
if (deletedIdsByTask.size > 0) {
|
|
293
|
+
await Promise.all(Array.from(deletedIdsByTask.entries()).map(async ([taskName, ids]) => {
|
|
294
|
+
if (ids.size === 0)
|
|
295
|
+
return;
|
|
296
|
+
const taskDef = this.registry.getTask(taskName);
|
|
297
|
+
if (taskDef) {
|
|
298
|
+
// We use deleteOrphanedTasks but limit it to the source IDs we just saw deleted.
|
|
299
|
+
// This reuses the EXACT same logic (including keepFor checks) as the background cleaner.
|
|
300
|
+
await taskDef.repository.deleteOrphanedTasks(taskName, taskDef.sourceCollection.collectionName, taskDef.filter || {}, taskDef.cleanupPolicyParsed, () => false, // shouldStop: immediate execution, no need to stop
|
|
301
|
+
Array.from(ids));
|
|
302
|
+
}
|
|
303
|
+
}));
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
async executeUpsertOperations(idsByCollection) {
|
|
307
|
+
if (idsByCollection.size > 0) {
|
|
308
|
+
await Promise.all(Array.from(idsByCollection.entries()).map(async ([collectionName, ids]) => {
|
|
309
|
+
if (ids.size === 0)
|
|
310
|
+
return;
|
|
311
|
+
try {
|
|
312
|
+
await this.ops.executePlanningPipeline(collectionName, Array.from(ids));
|
|
313
|
+
}
|
|
314
|
+
catch (error) {
|
|
315
|
+
this.onError(error);
|
|
316
|
+
}
|
|
317
|
+
}));
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
async handleStreamError(error) {
|
|
321
|
+
if (error.code === 280) {
|
|
322
|
+
this.onError(new Error(`Critical error: Oplog history lost(ChangeStreamHistoryLost).Resetting Resume Token.Original error: ${error.message} `));
|
|
323
|
+
await this.globalsCollection.updateOne({ _id: this.metaDocId }, { $unset: { 'streamState.resumeToken': '', reconciliation: '' } });
|
|
324
|
+
this.onInfo({
|
|
325
|
+
message: `Oplog lost, triggering reconciliation...`,
|
|
326
|
+
code: ReactiveTaskTypes_1.CODE_REACTIVE_TASK_PLANNER_RECONCILIATION_STARTED,
|
|
327
|
+
});
|
|
328
|
+
// Start stream first to capture new events
|
|
329
|
+
await this.startChangeStream();
|
|
330
|
+
if (this.changeStream) {
|
|
331
|
+
await this.reconciler.reconcile(this.isStoppedTester);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
this.onInfo({
|
|
336
|
+
message: `Change Stream error: ${error.message} `,
|
|
337
|
+
code: ReactiveTaskTypes_1.CODE_REACTIVE_TASK_PLANNER_STREAM_ERROR,
|
|
338
|
+
error: error.message,
|
|
339
|
+
});
|
|
340
|
+
this.callbacks.onStreamError();
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
async checkEvolutionStrategies() {
|
|
344
|
+
const metaDoc = (await this.globalsCollection.findOne({ _id: this.metaDocId }));
|
|
345
|
+
const storedTasks = (metaDoc === null || metaDoc === void 0 ? void 0 : metaDoc.tasks) || {};
|
|
346
|
+
const update = {};
|
|
347
|
+
const tasksToReconcile = [];
|
|
348
|
+
let needsUpdate = false;
|
|
349
|
+
const allTasks = this.registry.getAllTasks();
|
|
350
|
+
for (const taskDef of allTasks) {
|
|
351
|
+
const taskName = taskDef.task;
|
|
352
|
+
const defaultEvolution = {
|
|
353
|
+
handlerVersion: 1,
|
|
354
|
+
onHandlerVersionChange: 'none',
|
|
355
|
+
reconcileOnTriggerChange: true,
|
|
356
|
+
};
|
|
357
|
+
const evolution = Object.assign(Object.assign({}, defaultEvolution), (taskDef.evolution || {}));
|
|
358
|
+
const storedState = storedTasks[taskName];
|
|
359
|
+
const triggerChanged = this.checkTriggerEvolution(taskName, taskDef, evolution, storedState, update, tasksToReconcile);
|
|
360
|
+
if (triggerChanged)
|
|
361
|
+
needsUpdate = true;
|
|
362
|
+
const logicChanged = await this.checkLogicEvolution(taskName, taskDef, evolution, storedState, update);
|
|
363
|
+
if (logicChanged)
|
|
364
|
+
needsUpdate = true;
|
|
365
|
+
}
|
|
366
|
+
if (needsUpdate) {
|
|
367
|
+
debug(`[DEBUG] Updating meta doc with: `, JSON.stringify(update, null, 2));
|
|
368
|
+
await this.globalsCollection.updateOne({ _id: this.metaDocId }, update, { upsert: true });
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
debug(`[DEBUG] No updates needed for meta doc.`);
|
|
372
|
+
}
|
|
373
|
+
if (tasksToReconcile.length > 0) {
|
|
374
|
+
await this.reconciler.markAsUnreconciled(tasksToReconcile);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
checkTriggerEvolution(taskName, taskDef, evolution, storedState, update, tasksToReconcile) {
|
|
378
|
+
const currentTriggerConfig = {
|
|
379
|
+
filter: taskDef.filter || {},
|
|
380
|
+
watchProjection: taskDef.watchProjection || {},
|
|
381
|
+
};
|
|
382
|
+
const currentTriggerSig = stringify(currentTriggerConfig);
|
|
383
|
+
const storedTriggerSig = (storedState === null || storedState === void 0 ? void 0 : storedState.triggerConfig) ? stringify(storedState.triggerConfig) : null;
|
|
384
|
+
if (currentTriggerSig !== storedTriggerSig) {
|
|
385
|
+
const shouldReconcile = evolution.reconcileOnTriggerChange !== false;
|
|
386
|
+
const msg = storedTriggerSig === null ? `Initial trigger config captured for [${taskName}].` : `Trigger config changed for [${taskName}].`;
|
|
387
|
+
if (shouldReconcile) {
|
|
388
|
+
debug(`${msg} Queueing reconciliation.`);
|
|
389
|
+
tasksToReconcile.push(taskName);
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
debug(`[mongodash] ${msg} Reconciliation disabled.`);
|
|
393
|
+
}
|
|
394
|
+
if (!update.$set)
|
|
395
|
+
update.$set = {};
|
|
396
|
+
update.$set[`tasks.${taskName}.triggerConfig`] = currentTriggerConfig;
|
|
397
|
+
return true;
|
|
398
|
+
}
|
|
399
|
+
return false;
|
|
400
|
+
}
|
|
401
|
+
async checkLogicEvolution(taskName, taskDef, evolution, storedState, update) {
|
|
402
|
+
var _a, _b;
|
|
403
|
+
const currentVersion = (_a = evolution.handlerVersion) !== null && _a !== void 0 ? _a : 1;
|
|
404
|
+
const storedVersion = (_b = storedState === null || storedState === void 0 ? void 0 : storedState.handlerVersion) !== null && _b !== void 0 ? _b : (storedState ? 0 : 1);
|
|
405
|
+
if (currentVersion > storedVersion) {
|
|
406
|
+
const policy = evolution.onHandlerVersionChange || 'none';
|
|
407
|
+
debug(`Handler upgraded for [${taskName}](v${storedVersion} -> v${currentVersion}).Policy: ${policy} `);
|
|
408
|
+
const entry = this.registry.getEntry(taskDef.sourceCollection.collectionName);
|
|
409
|
+
if (entry) {
|
|
410
|
+
if (policy === 'reprocess_failed') {
|
|
411
|
+
await entry.repository.resetTasksForUpgrade(taskName, 'failed');
|
|
412
|
+
}
|
|
413
|
+
else if (policy === 'reprocess_all') {
|
|
414
|
+
await entry.repository.resetTasksForUpgrade(taskName, 'all');
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
if (!update.$set)
|
|
418
|
+
update.$set = {};
|
|
419
|
+
update.$set[`tasks.${taskName}.handlerVersion`] = currentVersion;
|
|
420
|
+
return true;
|
|
421
|
+
}
|
|
422
|
+
else if (currentVersion < storedVersion) {
|
|
423
|
+
debug(`[mongodash] ReactiveTask[${taskName}]: Current handlerVersion(${currentVersion}) is LOWER than stored version(${storedVersion}).Rollback detected ? `);
|
|
424
|
+
}
|
|
425
|
+
else if (!storedState && currentVersion === 1) {
|
|
426
|
+
// Safe Adoption
|
|
427
|
+
if (!update.$set)
|
|
428
|
+
update.$set = {};
|
|
429
|
+
update.$set[`tasks.${taskName}.handlerVersion`] = currentVersion;
|
|
430
|
+
return true;
|
|
431
|
+
}
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
exports.ReactiveTaskPlanner = ReactiveTaskPlanner;
|
|
436
|
+
//# sourceMappingURL=ReactiveTaskPlanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReactiveTaskPlanner.js","sourceRoot":"","sources":["../../../../src/reactiveTasks/ReactiveTaskPlanner.ts"],"names":[],"mappings":"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"}
|