Forráskód Böngészése

fix: Database Change no longer strands tied timestamps or hides unstamped documents

Truncating on maxDocuments now extends the slice through a shared
boundary timestamp instead of cutting through it, so documents tied
with the last reported one are no longer stranded past the strict >
comparison on the next run. Also logs a warning naming the count and
field when documents lack a readable timestampField value, since those
are silently unreportable by design once the mark advances past 0, and
the schema description now says so.
fszontagh 1 hónapja
szülő
commit
99e4aac2c2
1 módosított fájl, 28 hozzáadás és 4 törlés
  1. 28 4
      nodes/triggers/database-change.js

+ 28 - 4
nodes/triggers/database-change.js

@@ -18,7 +18,7 @@ const configSchema = {
         timestampField: {
             type: 'string',
             title: 'Timestamp Field',
-            description: 'Field holding the last-modified time. Defaults to the _updated_at the database maintains itself, in nanoseconds',
+            description: 'Field holding the last-modified time. Defaults to the _updated_at the database maintains itself, in nanoseconds. A document with no readable value in this field is never reported',
             default: '_updated_at'
         },
         filter: {
@@ -118,12 +118,24 @@ async function execute(config, input, context) {
     }
 
     let highWater = since;
+    let noStamp = 0;
     for (const document of documents) {
         const stamp = stampOf(document);
+        if (stamp === 0) {
+            noStamp++;
+        }
         if (stamp > highWater) {
             highWater = stamp;
         }
     }
+    if (noStamp > 0) {
+        // A document with no readable value in timestampField sorts as if it
+        // predates everything, and once the mark advances past 0 it can never
+        // satisfy the strict > filter below - it is never reported, silently,
+        // unless this is logged.
+        smartbotic.log.warn('Database Change: ' + noStamp + ' document(s) in ' + collection +
+            ' had no readable "' + timestampField + '" value and will never be reported');
+    }
 
     let changed = [];
     if (isFirstRun && config.emitOnFirstRun !== true) {
@@ -134,9 +146,21 @@ async function execute(config, input, context) {
             .filter(function (document) { return stampOf(document) > since; })
             .sort(function (left, right) { return stampOf(left) - stampOf(right); });
         if (changed.length > maxDocuments) {
-            smartbotic.log.warn('Database Change: ' + changed.length + ' documents changed, reporting the oldest ' +
-                maxDocuments + '. The rest arrive on the next run');
-            changed = changed.slice(0, maxDocuments);
+            let cut = maxDocuments;
+            const boundary = stampOf(changed[cut - 1]);
+            // Cutting through a group that shares one timestamp would strand
+            // the rest of that group: the mark advances to the shared stamp
+            // and the next run's strict > excludes them forever. The slice
+            // grows to take the whole tie, even though that overshoots the
+            // limit. If every changed document shares one stamp, cut grows to
+            // all of them, which is correct - nothing is stranded.
+            while (cut < changed.length && stampOf(changed[cut]) === boundary) {
+                cut++;
+            }
+            smartbotic.log.warn('Database Change: ' + changed.length + ' documents changed, reporting ' +
+                cut + (cut > maxDocuments ? ' (over the configured ' + maxDocuments + ', to avoid splitting a tied timestamp)' : '') +
+                '. The rest arrive on the next run');
+            changed = changed.slice(0, cut);
             // The mark only advances as far as what was actually reported, or
             // the remainder would be skipped rather than deferred.
             highWater = stampOf(changed[changed.length - 1]);