meadow-integration 1.0.26 → 1.0.28
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/package.json
CHANGED
|
@@ -715,7 +715,7 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
715
715
|
const tmpRecordID = pEntityRecord[this.DefaultIdentifier];
|
|
716
716
|
if (!tmpRecordID || tmpRecordID < 1)
|
|
717
717
|
{
|
|
718
|
-
return fRecordComplete
|
|
718
|
+
return setImmediate(fRecordComplete);
|
|
719
719
|
}
|
|
720
720
|
|
|
721
721
|
// Read local record with delete tracking disabled so we can see all records
|
|
@@ -745,7 +745,7 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
745
745
|
{
|
|
746
746
|
this.log.error(`Error creating deleted record ${this.EntitySchema.TableName} ID ${tmpRecordID}: ${pCreateError}`);
|
|
747
747
|
}
|
|
748
|
-
return fRecordComplete
|
|
748
|
+
return setImmediate(fRecordComplete);
|
|
749
749
|
});
|
|
750
750
|
return;
|
|
751
751
|
}
|
|
@@ -753,7 +753,7 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
753
753
|
if (pRecord.Deleted == 1)
|
|
754
754
|
{
|
|
755
755
|
// Already marked deleted locally
|
|
756
|
-
return fRecordComplete
|
|
756
|
+
return setImmediate(fRecordComplete);
|
|
757
757
|
}
|
|
758
758
|
|
|
759
759
|
// Record exists locally but is not deleted -- update it
|
|
@@ -772,7 +772,7 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
772
772
|
{
|
|
773
773
|
this.log.error(`Error marking record as deleted ${this.EntitySchema.TableName} ID ${tmpRecordID}: ${pUpdateError}`);
|
|
774
774
|
}
|
|
775
|
-
return fRecordComplete
|
|
775
|
+
return setImmediate(fRecordComplete);
|
|
776
776
|
});
|
|
777
777
|
});
|
|
778
778
|
},
|
|
@@ -138,6 +138,158 @@ class MeadowSyncEntityOngoingEventualConsistency extends libMeadowSyncEntityOngo
|
|
|
138
138
|
});
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
// Override deleted record sync with a time-budgeted version.
|
|
142
|
+
// The base syncDeletedRecords() walks ALL deleted records on the server
|
|
143
|
+
// with no limit, which defeats the purpose of eventual consistency.
|
|
144
|
+
// This version processes pages until BackSyncTimeLimit is exhausted.
|
|
145
|
+
syncDeletedRecords(fCallback)
|
|
146
|
+
{
|
|
147
|
+
const tmpDeletedColumn = this.EntitySchema.Columns.find((c) => c.Column == 'Deleted');
|
|
148
|
+
if (!tmpDeletedColumn)
|
|
149
|
+
{
|
|
150
|
+
this.fable.log.info(`No Deleted column for ${this.EntitySchema.TableName}; skipping delete sync.`);
|
|
151
|
+
return fCallback();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
this.fable.log.info(`Checking for deleted records on server for ${this.EntitySchema.TableName} (time-budgeted)...`);
|
|
155
|
+
|
|
156
|
+
this.fable.MeadowCloneRestClient.getJSON(this._appendDeletedQueryString(`${this.EntitySchema.TableName}s/Count/FilteredTo/FBV~Deleted~EQ~1`),
|
|
157
|
+
(pError, pResponse, pBody) =>
|
|
158
|
+
{
|
|
159
|
+
if (pError || !pBody || !pBody.hasOwnProperty('Count'))
|
|
160
|
+
{
|
|
161
|
+
this.fable.log.warn(`Could not get deleted record count for ${this.EntitySchema.TableName}; skipping delete sync.`);
|
|
162
|
+
return fCallback();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const tmpDeletedCount = pBody.Count;
|
|
166
|
+
if (tmpDeletedCount < 1)
|
|
167
|
+
{
|
|
168
|
+
this.fable.log.info(`No deleted records on server for ${this.EntitySchema.TableName}.`);
|
|
169
|
+
return fCallback();
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
this.fable.log.info(`Found ${tmpDeletedCount} deleted records on server for ${this.EntitySchema.TableName}; syncing deletions with ${this.BackSyncTimeLimit}ms budget...`);
|
|
173
|
+
|
|
174
|
+
let tmpDeleteCap = (this.MaxRecordsPerEntity > 0)
|
|
175
|
+
? Math.min(tmpDeletedCount, this.MaxRecordsPerEntity)
|
|
176
|
+
: tmpDeletedCount;
|
|
177
|
+
const tmpDeleteURLPartials = [];
|
|
178
|
+
for (let i = 0; i < tmpDeleteCap; i += this.PageSize)
|
|
179
|
+
{
|
|
180
|
+
tmpDeleteURLPartials.push(this._appendDeletedQueryString(`${this.EntitySchema.TableName}s/FilteredTo/FBV~Deleted~EQ~1~FSF~${this.DefaultIdentifier}~ASC~ASC/${i}/${this.PageSize}`));
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const tmpStartTime = Date.now();
|
|
184
|
+
let tmpProcessed = 0;
|
|
185
|
+
let tmpTimeBudgetExhausted = false;
|
|
186
|
+
|
|
187
|
+
this.fable.Utility.eachLimit(tmpDeleteURLPartials, 1,
|
|
188
|
+
(pURLPartial, fPageComplete) =>
|
|
189
|
+
{
|
|
190
|
+
// Check time budget before each page
|
|
191
|
+
if (Date.now() - tmpStartTime >= this.BackSyncTimeLimit)
|
|
192
|
+
{
|
|
193
|
+
tmpTimeBudgetExhausted = true;
|
|
194
|
+
return fPageComplete();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
this.fable.MeadowCloneRestClient.getJSON(pURLPartial,
|
|
198
|
+
(pDownloadError, pResponse, pBody) =>
|
|
199
|
+
{
|
|
200
|
+
if (pDownloadError || !pBody || !Array.isArray(pBody) || pBody.length < 1)
|
|
201
|
+
{
|
|
202
|
+
return fPageComplete();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
this.fable.Utility.eachLimit(pBody, 5,
|
|
206
|
+
(pEntityRecord, fRecordComplete) =>
|
|
207
|
+
{
|
|
208
|
+
const tmpRecordID = pEntityRecord[this.DefaultIdentifier];
|
|
209
|
+
if (!tmpRecordID || tmpRecordID < 1)
|
|
210
|
+
{
|
|
211
|
+
return setImmediate(fRecordComplete);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const tmpQuery = this.Meadow.query;
|
|
215
|
+
tmpQuery.addFilter(this.DefaultIdentifier, tmpRecordID);
|
|
216
|
+
tmpQuery.setDisableDeleteTracking(true);
|
|
217
|
+
|
|
218
|
+
this.Meadow.doRead(tmpQuery,
|
|
219
|
+
(pReadError, pQuery, pRecord) =>
|
|
220
|
+
{
|
|
221
|
+
if (pReadError || !pRecord)
|
|
222
|
+
{
|
|
223
|
+
const tmpRecordToCommit = this.marshalRecord(pEntityRecord);
|
|
224
|
+
|
|
225
|
+
const tmpCreateQuery = this.Meadow.query.addRecord(tmpRecordToCommit);
|
|
226
|
+
tmpCreateQuery.setDisableAutoIdentity(true);
|
|
227
|
+
tmpCreateQuery.setDisableAutoDateStamp(true);
|
|
228
|
+
tmpCreateQuery.setDisableAutoUserStamp(true);
|
|
229
|
+
tmpCreateQuery.setDisableDeleteTracking(true);
|
|
230
|
+
tmpCreateQuery.AllowIdentityInsert = true;
|
|
231
|
+
|
|
232
|
+
this.Meadow.doCreate(tmpCreateQuery,
|
|
233
|
+
(pCreateError) =>
|
|
234
|
+
{
|
|
235
|
+
if (pCreateError)
|
|
236
|
+
{
|
|
237
|
+
this.log.error(`Error creating deleted record ${this.EntitySchema.TableName} ID ${tmpRecordID}: ${pCreateError}`);
|
|
238
|
+
}
|
|
239
|
+
tmpProcessed++;
|
|
240
|
+
return setImmediate(fRecordComplete);
|
|
241
|
+
});
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (pRecord.Deleted == 1)
|
|
246
|
+
{
|
|
247
|
+
tmpProcessed++;
|
|
248
|
+
return setImmediate(fRecordComplete);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const tmpRecordToCommit = this.marshalRecord(pEntityRecord);
|
|
252
|
+
|
|
253
|
+
const tmpUpdateQuery = this.Meadow.query.addRecord(tmpRecordToCommit);
|
|
254
|
+
tmpUpdateQuery.setDisableAutoIdentity(true);
|
|
255
|
+
tmpUpdateQuery.setDisableAutoDateStamp(true);
|
|
256
|
+
tmpUpdateQuery.setDisableAutoUserStamp(true);
|
|
257
|
+
tmpUpdateQuery.setDisableDeleteTracking(true);
|
|
258
|
+
|
|
259
|
+
this.Meadow.doUpdate(tmpUpdateQuery,
|
|
260
|
+
(pUpdateError) =>
|
|
261
|
+
{
|
|
262
|
+
if (pUpdateError)
|
|
263
|
+
{
|
|
264
|
+
this.log.error(`Error marking record as deleted ${this.EntitySchema.TableName} ID ${tmpRecordID}: ${pUpdateError}`);
|
|
265
|
+
}
|
|
266
|
+
tmpProcessed++;
|
|
267
|
+
return setImmediate(fRecordComplete);
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
},
|
|
271
|
+
(pRecordSyncError) =>
|
|
272
|
+
{
|
|
273
|
+
return fPageComplete();
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
},
|
|
277
|
+
(pDeleteSyncError) =>
|
|
278
|
+
{
|
|
279
|
+
const tmpElapsed = Date.now() - tmpStartTime;
|
|
280
|
+
if (tmpTimeBudgetExhausted)
|
|
281
|
+
{
|
|
282
|
+
this.fable.log.info(`Delete sync time budget exhausted for ${this.EntitySchema.TableName} after ${tmpElapsed}ms (${tmpProcessed} of ${tmpDeletedCount} deleted records processed).`);
|
|
283
|
+
}
|
|
284
|
+
else
|
|
285
|
+
{
|
|
286
|
+
this.fable.log.info(`Delete sync complete for ${this.EntitySchema.TableName} (${tmpProcessed} of ${tmpDeletedCount} deleted records processed in ${tmpElapsed}ms).`);
|
|
287
|
+
}
|
|
288
|
+
return fCallback();
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
|
|
141
293
|
_syncInternal(fCallback)
|
|
142
294
|
{
|
|
143
295
|
this.operation.createTimeStamp('EntityOngoingEventualConsistencySync');
|