@resolveio/server-lib 20.13.1 → 20.13.2

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.
@@ -13,6 +13,10 @@ export declare class SubscriptionManager {
13
13
  private _mongoQueue;
14
14
  private _mongoQueueId;
15
15
  private _oplog$;
16
+ private _oplogMode;
17
+ private _useLocalOplog;
18
+ private _localOplogResyncIntervalMs;
19
+ private _localOplogResyncTimer;
16
20
  private _nodeCache;
17
21
  private _cacheId;
18
22
  private _heapSize;
@@ -69,6 +73,13 @@ export declare class SubscriptionManager {
69
73
  getActiveSubscriptions(): ActiveSubscriptionModel[];
70
74
  private getPublicationCollections;
71
75
  private getWatchedDatabases;
76
+ private resolveOplogMode;
77
+ private resolveLocalOplogResyncIntervalMs;
78
+ private parsePositiveNumber;
79
+ private isChangeStreamUnsupported;
80
+ private enableLocalOplogFallback;
81
+ getUseLocalOplog(): boolean;
82
+ notifyLocalOplog(collection: string, type?: string): void;
72
83
  private getResumeTokenDocId;
73
84
  private loadResumeToken;
74
85
  private saveResumeToken;
@@ -124,6 +124,10 @@ var SubscriptionManager = /** @class */ (function () {
124
124
  this._lastRouteBySocket = new Map();
125
125
  this._mongoQueue = [];
126
126
  this._mongoQueueId = 0;
127
+ this._oplogMode = 'auto';
128
+ this._useLocalOplog = false;
129
+ this._localOplogResyncIntervalMs = 0;
130
+ this._localOplogResyncTimer = null;
127
131
  this._cacheId = 1;
128
132
  this._heapSize = resolveHeapLimitBytes();
129
133
  this._enableDebug = false;
@@ -204,6 +208,8 @@ var SubscriptionManager = /** @class */ (function () {
204
208
  // }, 10000);
205
209
  this.serverConfig = serverConfig;
206
210
  this._wss = wss;
211
+ this._oplogMode = this.resolveOplogMode();
212
+ this._localOplogResyncIntervalMs = this.resolveLocalOplogResyncIntervalMs();
207
213
  // Publications
208
214
  (0, super_admin_1.loadSuperAdminPublications)(this);
209
215
  (0, app_status_1.loadAppStatusPublications)(this);
@@ -218,12 +224,19 @@ var SubscriptionManager = /** @class */ (function () {
218
224
  (0, user_groups_1.loadUserGroupPublications)(this);
219
225
  (0, user_guides_1.loadUserGuidePublications)(this);
220
226
  (0, report_builder_dashboard_builders_1.loadReportBuilderDashboardBuilderPublications)(this);
221
- return [4 /*yield*/, this.loadResumeToken()];
227
+ if (!(this._oplogMode === 'local')) return [3 /*break*/, 2];
228
+ return [4 /*yield*/, this.enableLocalOplogFallback('config')];
222
229
  case 1:
230
+ _a.sent();
231
+ return [3 /*break*/, 5];
232
+ case 2: return [4 /*yield*/, this.loadResumeToken()];
233
+ case 3:
223
234
  resumeToken = _a.sent();
224
235
  return [4 /*yield*/, this.tailOpLog(resumeToken || undefined)];
225
- case 2:
236
+ case 4:
226
237
  _a.sent();
238
+ _a.label = 5;
239
+ case 5:
227
240
  setInterval(function () {
228
241
  _this._oplogRetryCount = 0;
229
242
  }, 15000);
@@ -330,10 +343,10 @@ var SubscriptionManager = /** @class */ (function () {
330
343
  });
331
344
  }); }, 30000);
332
345
  return [4 /*yield*/, flag_collection_1.Flags.findOne({ type: 'Enable Debug' })];
333
- case 3:
346
+ case 6:
334
347
  flag = _a.sent();
335
348
  return [4 /*yield*/, flag_collection_1.Flags.findOne({ type: 'Enable Dependency Debug' })];
336
- case 4:
349
+ case 7:
337
350
  dependencyFlag = _a.sent();
338
351
  if (flag && flag.value) {
339
352
  this._enableDebug = true;
@@ -430,7 +443,7 @@ var SubscriptionManager = /** @class */ (function () {
430
443
  }
431
444
  events = queued.events;
432
445
  // Original invalidation logic
433
- resolveio_server_app_1.ResolveIOServer.getMongoManager().invalidateQueryCache(collection);
446
+ resolveio_server_app_1.ResolveIOServer.getMongoManager().invalidateQueryCache(collection, true);
434
447
  collSubs = this._subscriptions.filter(function (sub) { return _this.subscriptionReferencesCollection(sub, collection); });
435
448
  _f.label = 1;
436
449
  case 1:
@@ -937,6 +950,128 @@ var SubscriptionManager = /** @class */ (function () {
937
950
  var mainDb = config && typeof config['DATABASE'] === 'string' ? config['DATABASE'] : '';
938
951
  return mainDb ? [mainDb] : [];
939
952
  };
953
+ SubscriptionManager.prototype.resolveOplogMode = function () {
954
+ var config = this.serverConfig || resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
955
+ var raw = process.env.SUBSCRIPTION_OPLOG_MODE || process.env.OPLOG_MODE || config['SUBSCRIPTION_OPLOG_MODE'] || config['OPLOG_MODE'];
956
+ if (typeof raw !== 'string' || !raw.trim()) {
957
+ return 'auto';
958
+ }
959
+ var normalized = raw.trim().toLowerCase();
960
+ if (['local', 'single', 'standalone', 'fallback', 'poll'].includes(normalized)) {
961
+ return 'local';
962
+ }
963
+ if (['change-stream', 'changestream', 'oplog', 'replica', 'replicaset', 'rs'].includes(normalized)) {
964
+ return 'change-stream';
965
+ }
966
+ return 'auto';
967
+ };
968
+ SubscriptionManager.prototype.resolveLocalOplogResyncIntervalMs = function () {
969
+ var config = this.serverConfig || resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
970
+ var raw = process.env.OPLOG_FALLBACK_RESYNC_MS
971
+ || process.env.SUBSCRIPTION_OPLOG_RESYNC_MS
972
+ || config['OPLOG_FALLBACK_RESYNC_MS']
973
+ || config['SUBSCRIPTION_OPLOG_RESYNC_MS'];
974
+ return this.parsePositiveNumber(raw);
975
+ };
976
+ SubscriptionManager.prototype.parsePositiveNumber = function (value) {
977
+ if (typeof value === 'number' && Number.isFinite(value) && value > 0) {
978
+ return value;
979
+ }
980
+ if (typeof value === 'string' && value.trim().length) {
981
+ var parsed = parseInt(value, 10);
982
+ if (Number.isFinite(parsed) && parsed > 0) {
983
+ return parsed;
984
+ }
985
+ }
986
+ return 0;
987
+ };
988
+ SubscriptionManager.prototype.isChangeStreamUnsupported = function (error) {
989
+ var code = typeof (error === null || error === void 0 ? void 0 : error.code) === 'number' ? error.code : null;
990
+ var codeName = typeof (error === null || error === void 0 ? void 0 : error.codeName) === 'string' ? error.codeName.toLowerCase() : '';
991
+ var message = typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' ? error.message.toLowerCase() : '';
992
+ if (code === 40573) {
993
+ return true;
994
+ }
995
+ if (codeName && codeName.includes('changestream')) {
996
+ return true;
997
+ }
998
+ if (message.includes('change stream') && message.includes('replica')) {
999
+ return true;
1000
+ }
1001
+ if (message.includes('change stream') && message.includes('not supported')) {
1002
+ return true;
1003
+ }
1004
+ return false;
1005
+ };
1006
+ SubscriptionManager.prototype.enableLocalOplogFallback = function (reason, error) {
1007
+ return __awaiter(this, void 0, void 0, function () {
1008
+ var _a, message;
1009
+ var _this = this;
1010
+ return __generator(this, function (_b) {
1011
+ switch (_b.label) {
1012
+ case 0:
1013
+ if (this._useLocalOplog) {
1014
+ return [2 /*return*/];
1015
+ }
1016
+ this._useLocalOplog = true;
1017
+ this._oplogMode = 'local';
1018
+ this._oplogRetryCount = 0;
1019
+ if (!(this._oplog$ && !this._oplog$.closed)) return [3 /*break*/, 5];
1020
+ _b.label = 1;
1021
+ case 1:
1022
+ _b.trys.push([1, 3, , 4]);
1023
+ this._oplog$.removeAllListeners();
1024
+ return [4 /*yield*/, this._oplog$.close()];
1025
+ case 2:
1026
+ _b.sent();
1027
+ return [3 /*break*/, 4];
1028
+ case 3:
1029
+ _a = _b.sent();
1030
+ return [3 /*break*/, 4];
1031
+ case 4:
1032
+ this._oplog$ = null;
1033
+ _b.label = 5;
1034
+ case 5:
1035
+ message = typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' ? error.message : '';
1036
+ console.log(new Date(), 'oplog fallback enabled', reason, message ? "(".concat(message, ")") : '');
1037
+ this.queueFullResync('oplog-fallback-enabled');
1038
+ if (this._localOplogResyncIntervalMs > 0 && !this._localOplogResyncTimer) {
1039
+ this._localOplogResyncTimer = setInterval(function () {
1040
+ _this.queueFullResync('oplog-fallback-poll');
1041
+ }, this._localOplogResyncIntervalMs);
1042
+ }
1043
+ return [2 /*return*/];
1044
+ }
1045
+ });
1046
+ });
1047
+ };
1048
+ SubscriptionManager.prototype.getUseLocalOplog = function () {
1049
+ return this._useLocalOplog;
1050
+ };
1051
+ SubscriptionManager.prototype.notifyLocalOplog = function (collection, type) {
1052
+ var _this = this;
1053
+ if (type === void 0) { type = 'update'; }
1054
+ if (!this._useLocalOplog) {
1055
+ return;
1056
+ }
1057
+ setImmediate(function () { return __awaiter(_this, void 0, void 0, function () {
1058
+ var _a;
1059
+ return __generator(this, function (_b) {
1060
+ switch (_b.label) {
1061
+ case 0:
1062
+ _b.trys.push([0, 2, , 3]);
1063
+ return [4 /*yield*/, this.invalidatePubsCache(collection, type)];
1064
+ case 1:
1065
+ _b.sent();
1066
+ return [3 /*break*/, 3];
1067
+ case 2:
1068
+ _a = _b.sent();
1069
+ return [3 /*break*/, 3];
1070
+ case 3: return [2 /*return*/];
1071
+ }
1072
+ });
1073
+ }); });
1074
+ };
940
1075
  SubscriptionManager.prototype.getResumeTokenDocId = function () {
941
1076
  if (process.env.NODE_APP_INSTANCE) {
942
1077
  return "oplog:".concat(process.env.NODE_APP_INSTANCE);
@@ -1194,11 +1329,14 @@ var SubscriptionManager = /** @class */ (function () {
1194
1329
  // Watch (tail) Mongo's operation log on the entire database (all insert/modify/delete will trigger this function)
1195
1330
  SubscriptionManager.prototype.tailOpLog = function (resumeToken) {
1196
1331
  return __awaiter(this, void 0, void 0, function () {
1197
- var watchDatabases, pipeline, lastResumeToken_1, startedWithResumeToken, error_6;
1332
+ var watchDatabases, pipeline, lastResumeToken_1, startedWithResumeToken, error_6, innerError_1, error_7;
1198
1333
  var _this = this;
1199
1334
  return __generator(this, function (_a) {
1200
1335
  switch (_a.label) {
1201
1336
  case 0:
1337
+ if (this._useLocalOplog) {
1338
+ return [2 /*return*/];
1339
+ }
1202
1340
  if (!(this._oplog$ && !this._oplog$.closed)) return [3 /*break*/, 2];
1203
1341
  this._oplog$.removeAllListeners();
1204
1342
  return [4 /*yield*/, this._oplog$.close()];
@@ -1212,7 +1350,7 @@ var SubscriptionManager = /** @class */ (function () {
1212
1350
  case 3:
1213
1351
  // eslint-disable-next-line no-restricted-syntax
1214
1352
  _a.sent();
1215
- if (!(!this._oplog$ || this._oplog$.closed)) return [3 /*break*/, 12];
1353
+ if (!(!this._oplog$ || this._oplog$.closed)) return [3 /*break*/, 22];
1216
1354
  this._oplogRetryCount += 1;
1217
1355
  if (this._oplogRetryCount > 5) {
1218
1356
  console.error('****************** TAIL OPLOG ERROR, RETRYING A BUNCH OF TIMES, KILLING PROCESS **************************');
@@ -1243,37 +1381,65 @@ var SubscriptionManager = /** @class */ (function () {
1243
1381
  },
1244
1382
  ];
1245
1383
  startedWithResumeToken = false;
1246
- if (!resumeToken) return [3 /*break*/, 10];
1384
+ if (!resumeToken) return [3 /*break*/, 17];
1247
1385
  lastResumeToken_1 = resumeToken;
1248
1386
  _a.label = 4;
1249
1387
  case 4:
1250
- _a.trys.push([4, 5, , 9]);
1388
+ _a.trys.push([4, 5, , 16]);
1251
1389
  this._oplog$ = resolveio_server_app_1.ResolveIOServer.getMongoConnection().watch(pipeline, { resumeAfter: resumeToken, fullDocument: 'updateLookup' });
1252
1390
  startedWithResumeToken = true;
1253
- return [3 /*break*/, 9];
1391
+ return [3 /*break*/, 16];
1254
1392
  case 5:
1255
1393
  error_6 = _a.sent();
1256
- if (!this._oplog$) return [3 /*break*/, 7];
1394
+ if (!this.isChangeStreamUnsupported(error_6)) return [3 /*break*/, 7];
1395
+ return [4 /*yield*/, this.enableLocalOplogFallback('change-stream-unsupported', error_6)];
1396
+ case 6:
1397
+ _a.sent();
1398
+ return [2 /*return*/];
1399
+ case 7:
1400
+ if (!this._oplog$) return [3 /*break*/, 9];
1257
1401
  this._oplog$.removeAllListeners();
1258
1402
  return [4 /*yield*/, this._oplog$.close()];
1259
- case 6:
1403
+ case 8:
1260
1404
  _a.sent();
1261
1405
  this._oplog$ = null;
1262
- _a.label = 7;
1263
- case 7: return [4 /*yield*/, this.clearResumeToken()];
1264
- case 8:
1406
+ _a.label = 9;
1407
+ case 9: return [4 /*yield*/, this.clearResumeToken()];
1408
+ case 10:
1265
1409
  _a.sent();
1266
1410
  lastResumeToken_1 = null;
1267
1411
  console.log(new Date(), 'oplog resumeAfter failed, starting fresh', error_6);
1412
+ _a.label = 11;
1413
+ case 11:
1414
+ _a.trys.push([11, 12, , 15]);
1268
1415
  this._oplog$ = resolveio_server_app_1.ResolveIOServer.getMongoConnection().watch(pipeline, { fullDocument: 'updateLookup' });
1269
1416
  startedWithResumeToken = false;
1417
+ return [3 /*break*/, 15];
1418
+ case 12:
1419
+ innerError_1 = _a.sent();
1420
+ if (!this.isChangeStreamUnsupported(innerError_1)) return [3 /*break*/, 14];
1421
+ return [4 /*yield*/, this.enableLocalOplogFallback('change-stream-unsupported', innerError_1)];
1422
+ case 13:
1423
+ _a.sent();
1424
+ return [2 /*return*/];
1425
+ case 14: throw innerError_1;
1426
+ case 15:
1270
1427
  this.queueFullResync('oplog-resumeAfter-failed');
1271
- return [3 /*break*/, 9];
1272
- case 9: return [3 /*break*/, 11];
1273
- case 10:
1428
+ return [3 /*break*/, 16];
1429
+ case 16: return [3 /*break*/, 21];
1430
+ case 17:
1431
+ _a.trys.push([17, 18, , 21]);
1274
1432
  this._oplog$ = resolveio_server_app_1.ResolveIOServer.getMongoConnection().watch(pipeline, { fullDocument: 'updateLookup' });
1275
- _a.label = 11;
1276
- case 11:
1433
+ return [3 /*break*/, 21];
1434
+ case 18:
1435
+ error_7 = _a.sent();
1436
+ if (!this.isChangeStreamUnsupported(error_7)) return [3 /*break*/, 20];
1437
+ return [4 /*yield*/, this.enableLocalOplogFallback('change-stream-unsupported', error_7)];
1438
+ case 19:
1439
+ _a.sent();
1440
+ return [2 /*return*/];
1441
+ case 20: throw error_7;
1442
+ case 21:
1277
1443
  console.log(new Date(), 'oplog started', startedWithResumeToken ? '(resumeAfter)' : '');
1278
1444
  this._oplog$.on('change', function (doc) { return __awaiter(_this, void 0, void 0, function () {
1279
1445
  var collection, fullDocument, docId, flag, dependencyFlag;
@@ -1365,10 +1531,15 @@ var SubscriptionManager = /** @class */ (function () {
1365
1531
  switch (_a.label) {
1366
1532
  case 0:
1367
1533
  console.log(new Date(), 'oplog error', error);
1368
- return [4 /*yield*/, this._oplog$.close()];
1534
+ if (!this.isChangeStreamUnsupported(error)) return [3 /*break*/, 2];
1535
+ return [4 /*yield*/, this.enableLocalOplogFallback('change-stream-unsupported', error)];
1369
1536
  case 1:
1370
1537
  _a.sent();
1371
1538
  return [2 /*return*/];
1539
+ case 2: return [4 /*yield*/, this._oplog$.close()];
1540
+ case 3:
1541
+ _a.sent();
1542
+ return [2 /*return*/];
1372
1543
  }
1373
1544
  });
1374
1545
  }); });
@@ -1399,8 +1570,8 @@ var SubscriptionManager = /** @class */ (function () {
1399
1570
  }
1400
1571
  });
1401
1572
  }); });
1402
- _a.label = 12;
1403
- case 12: return [2 /*return*/];
1573
+ _a.label = 22;
1574
+ case 22: return [2 /*return*/];
1404
1575
  }
1405
1576
  });
1406
1577
  });