meadow-integration 1.0.7 → 1.0.9

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "meadow-integration",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "Meadow Data Integration",
5
5
  "bin": {
6
6
  "mdwint": "source/cli/Meadow-Integration-CLI-Run.js"
@@ -16,7 +16,7 @@
16
16
  "author": "steven velozo <steven@velozo.com>",
17
17
  "license": "MIT",
18
18
  "devDependencies": {
19
- "quackage": "^1.0.61"
19
+ "quackage": "^1.0.63"
20
20
  },
21
21
  "mocha": {
22
22
  "diff": true,
@@ -39,9 +39,9 @@
39
39
  "dependencies": {
40
40
  "fable": "^3.1.63",
41
41
  "fable-serviceproviderbase": "^3.0.19",
42
- "meadow": "^2.0.28",
43
- "meadow-connection-mysql": "^1.0.13",
44
- "meadow-connection-mssql": "^1.0.15",
42
+ "meadow": "^2.0.30",
43
+ "meadow-connection-mysql": "^1.0.14",
44
+ "meadow-connection-mssql": "^1.0.16",
45
45
  "orator": "^6.0.4",
46
46
  "orator-serviceserver-restify": "^2.0.9",
47
47
  "pict-service-commandlineutility": "^1.0.19"
@@ -6,6 +6,14 @@ const defaultRestClientOptions = (
6
6
  {
7
7
  DownloadBatchSize: 100,
8
8
 
9
+ // Request timeout in milliseconds for normal remote API calls.
10
+ // Default: 60 seconds.
11
+ RequestTimeout: 60000,
12
+
13
+ // Request timeout in milliseconds for MAX(column) queries,
14
+ // which can be very slow on large tables. Default: 5 minutes.
15
+ MaxRequestTimeout: 300000,
16
+
9
17
  ServerURL: 'https://localhost:8080/1.0/',
10
18
  UserID: false,
11
19
  Password: false,
@@ -36,7 +44,12 @@ class MeadowCloneRestClient extends libFableServiceProviderBase
36
44
  this.restClient = this.fable.serviceManager.instantiateServiceProvider('RestClient', {}, 'MeadowCloneRestClient-RestClient');
37
45
  this.cache = {};
38
46
 
39
- const agentOptions = { keepAlive: true };
47
+ this.requestTimeout = this.options.RequestTimeout;
48
+ this.maxRequestTimeout = this.options.MaxRequestTimeout;
49
+
50
+ // Use the longer of the two timeouts for the agent's socket timeout
51
+ // so that MAX queries don't get killed at the socket level.
52
+ const agentOptions = { keepAlive: true, timeout: Math.max(this.requestTimeout, this.maxRequestTimeout) };
40
53
 
41
54
  if (this.serverURL && this.serverURL.startsWith('http:'))
42
55
  {
@@ -53,12 +53,29 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
53
53
  this.Meadow = this.fable.Meadow.loadFromPackageObject(this.EntitySchema.MeadowSchema);
54
54
  }
55
55
 
56
- this.log.info(`Sync for ${this.EntitySchema.TableName} creating table if it doesn't exist...`);
57
-
58
56
  if (this.Meadow && this.Meadow.provider)
59
57
  {
60
- return this.Meadow.provider.getProvider().createTable(this.EntitySchema, (pCreateError) =>
58
+ let tmpProvider = this.Meadow.provider.getProvider();
59
+
60
+ if (!tmpProvider)
61
+ {
62
+ this.log.error(`No provider returned by getProvider() for ${this.EntitySchema.TableName}`);
63
+ return fCallback(new Error(`No provider returned by getProvider() for ${this.EntitySchema.TableName}`));
64
+ }
65
+
66
+ if (!tmpProvider.createTable)
61
67
  {
68
+ this.log.error(`Provider for ${this.EntitySchema.TableName} has no createTable method.`);
69
+ return fCallback(new Error(`Provider for ${this.EntitySchema.TableName} has no createTable method`));
70
+ }
71
+
72
+ return tmpProvider.createTable(this.EntitySchema, (pCreateError) =>
73
+ {
74
+ if (pCreateError)
75
+ {
76
+ this.log.warn(`${this.EntitySchema.TableName}: createTable returned error: ${pCreateError}`);
77
+ }
78
+
62
79
  const tmpGUIDColumn = this.EntitySchema.Columns.find((c) => c.DataType == 'GUID');
63
80
  const tmpDeletedColumn = this.EntitySchema.Columns.find((c) => c.Column == 'Deleted');
64
81
 
@@ -91,9 +108,17 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
91
108
  return this.fable.MeadowConnectionManager.createIndex(this.EntitySchema, tmpDeletedColumn, false, fNext);
92
109
  });
93
110
  }
94
- tmpAnticipate.wait(fCallback);
111
+ tmpAnticipate.wait((pIndexError) =>
112
+ {
113
+ if (pIndexError)
114
+ {
115
+ this.log.warn(`${this.EntitySchema.TableName}: Index creation error: ${pIndexError}`);
116
+ }
117
+ return fCallback(pIndexError || pCreateError);
118
+ });
95
119
  });
96
120
  }
121
+
97
122
  return fCallback();
98
123
  }
99
124
 
@@ -274,6 +299,8 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
274
299
  {
275
300
  this.operation.createTimeStamp('EntityInitialSync');
276
301
 
302
+ this.log.info(`Syncing ${this.EntitySchema.TableName} (PageSize: ${this.PageSize}, SyncDeletedRecords: ${this.SyncDeletedRecords})`);
303
+
277
304
  const tmpSyncState = (
278
305
  {
279
306
  Local: { MaxIDEntity: -1, RecordCount: 0 },
@@ -293,16 +320,12 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
293
320
  {
294
321
  if (pReadError)
295
322
  {
296
- this.fable.log.error(`Error reading local max entity ID ${this.EntitySchema.TableName}: ${pReadError}`, { Error: pReadError });
297
323
  return fStageComplete(`Error reading local max entity ID ${this.EntitySchema.TableName}: ${pReadError}`);
298
324
  }
299
- if (!pRecord)
325
+ if (pRecord)
300
326
  {
301
- this.fable.log.warn(`No records found in local ${this.EntitySchema.TableName}.`);
302
- return fStageComplete();
327
+ tmpSyncState.Local.MaxIDEntity = pRecord[this.DefaultIdentifier];
303
328
  }
304
- this.fable.log.info(`Found local max entity ID ${this.EntitySchema.TableName}: ${pRecord[this.DefaultIdentifier]}`);
305
- tmpSyncState.Local.MaxIDEntity = pRecord[this.DefaultIdentifier];
306
329
  return fStageComplete();
307
330
  });
308
331
  },
@@ -315,7 +338,6 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
315
338
  {
316
339
  if (pCountError)
317
340
  {
318
- this.fable.log.error(`Error getting local count of ${this.EntitySchema.TableName}: ${pCountError}`, { Error: pCountError });
319
341
  return fStageComplete(`Error getting local count of ${this.EntitySchema.TableName}: ${pCountError}`);
320
342
  }
321
343
  tmpSyncState.Local.RecordCount = pCount;
@@ -330,18 +352,12 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
330
352
  {
331
353
  if (pError)
332
354
  {
333
- this.fable.log.error(`Error getting server max entity ID ${this.EntitySchema.TableName}: ${pError}`, { Error: pError });
334
355
  return fStageComplete(`Error getting server max entity ID ${this.EntitySchema.TableName}: ${pError}`);
335
356
  }
336
357
  if (pBody && pBody.hasOwnProperty(this.DefaultIdentifier))
337
358
  {
338
- this.fable.log.info(`Found server max entity ID ${this.EntitySchema.TableName}: ${pBody[this.DefaultIdentifier]}`);
339
359
  tmpSyncState.Server.MaxIDEntity = pBody[this.DefaultIdentifier];
340
360
  }
341
- else
342
- {
343
- this.fable.log.warn(`No records found in server for max entity ID of ${this.EntitySchema.TableName}.`);
344
- }
345
361
  return fStageComplete();
346
362
  });
347
363
  },
@@ -353,18 +369,12 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
353
369
  {
354
370
  if (pError)
355
371
  {
356
- this.fable.log.error(`Error getting server count for ${this.EntitySchema.TableName}: ${pError}`, { Error: pError });
357
372
  return fStageComplete(`Error getting server count for ${this.EntitySchema.TableName}: ${pError}`);
358
373
  }
359
374
  if (pBody && pBody.hasOwnProperty('Count'))
360
375
  {
361
- this.fable.log.info(`Found server count for ${this.EntitySchema.TableName}: ${pBody.Count}`);
362
376
  tmpSyncState.Server.RecordCount = pBody.Count;
363
377
  }
364
- else
365
- {
366
- this.fable.log.warn(`No records found in server based on count for ${this.EntitySchema.TableName}.`);
367
- }
368
378
  return fStageComplete();
369
379
  });
370
380
  },
@@ -382,21 +392,28 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
382
392
  tmpSyncState.URLPartials.push(`${this.EntitySchema.TableName}s/FilteredTo/FBV~${this.DefaultIdentifier}~GT~${tmpSyncState.Local.MaxIDEntity}~FSF~${this.DefaultIdentifier}~ASC~ASC/${i}/${this.PageSize}`);
383
393
  }
384
394
 
385
- this.fable.log.info(`Syncing with ${tmpSyncState.URLPartials.length} requests for ${this.EntitySchema.TableName} with local max ID ${tmpSyncState.Local.MaxIDEntity} and server max ID ${tmpSyncState.Server.MaxIDEntity}; estimated ${tmpSyncState.EstimatedRecordCount} records to sync.`);
395
+ this.fable.log.info(`${this.EntitySchema.TableName}: downloading ${tmpSyncState.URLPartials.length} pages (local: ${tmpSyncState.Local.RecordCount}/${tmpSyncState.Local.MaxIDEntity}, server: ${tmpSyncState.Server.RecordCount}/${tmpSyncState.Server.MaxIDEntity}, estimated new: ${tmpSyncState.EstimatedRecordCount})`);
386
396
 
387
397
  return fStageComplete();
388
398
  },
389
399
  (fStageComplete) =>
390
400
  {
401
+ let tmpPageIndex = 0;
402
+ let tmpRecordsCreated = 0;
403
+ let tmpRecordsSkipped = 0;
404
+ let tmpRecordsErrored = 0;
405
+
391
406
  this.fable.Utility.eachLimit(tmpSyncState.URLPartials, 1,
392
407
  (pURLPartial, fDownloadComplete) =>
393
408
  {
409
+ tmpPageIndex++;
410
+
394
411
  this.fable.MeadowCloneRestClient.getJSON(pURLPartial,
395
412
  (pDownloadError, pResponse, pBody) =>
396
413
  {
397
414
  if (pDownloadError)
398
415
  {
399
- this.fable.log.error(`Error getting URL Partial [${pURLPartial}]: ${pDownloadError}`, { Error: pDownloadError });
416
+ this.fable.log.error(`${this.EntitySchema.TableName}: page ${tmpPageIndex} download error: ${pDownloadError}`);
400
417
  return fDownloadComplete();
401
418
  }
402
419
  if (pBody && pBody.length > 0)
@@ -417,7 +434,7 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
417
434
  {
418
435
  if (pReadError)
419
436
  {
420
- this.fable.log.error(`Error reading record ${this.EntitySchema.TableName}: ${pReadError}`, { Error: pReadError, PassedRecord: tmpRecord });
437
+ tmpRecordsErrored++;
421
438
  return fEntitySyncComplete();
422
439
  }
423
440
  if (!pRecord)
@@ -439,15 +456,18 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
439
456
  {
440
457
  if (pCreateError)
441
458
  {
442
- this.log.error(`Error creating record ${this.EntitySchema.TableName}: ${pCreateError}`, pCreateError);
459
+ tmpRecordsErrored++;
460
+ this.log.error(`${this.EntitySchema.TableName}: doCreate error for ID ${tmpRecord[this.DefaultIdentifier]}: ${pCreateError}`);
443
461
  return fEntitySyncComplete();
444
462
  }
463
+ tmpRecordsCreated++;
445
464
  this.operation.incrementProgressTrackerStatus(`FullSync-${this.EntitySchema.TableName}`, 1);
446
465
  return fEntitySyncComplete();
447
466
  });
448
467
  }
449
468
  else
450
469
  {
470
+ tmpRecordsSkipped++;
451
471
  return fEntitySyncComplete();
452
472
  }
453
473
  });
@@ -474,6 +494,7 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
474
494
  },
475
495
  (pDownloadError) =>
476
496
  {
497
+ this.fable.log.info(`${this.EntitySchema.TableName}: sync complete — created: ${tmpRecordsCreated}, skipped: ${tmpRecordsSkipped}, errors: ${tmpRecordsErrored}`);
477
498
  if (pDownloadError)
478
499
  {
479
500
  this.fable.log.error(`Error returned URL Partial .. this may not be an error: ${pDownloadError}`);
@@ -486,7 +507,7 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
486
507
  {
487
508
  if (pError)
488
509
  {
489
- this.fable.log.error(`Error performing sync ${this.EntitySchema.TableName}: ${pError}`, { Error: pError });
510
+ this.fable.log.error(`${this.EntitySchema.TableName}: sync error: ${pError}`);
490
511
  }
491
512
 
492
513
  if (this.SyncDeletedRecords)
@@ -70,9 +70,16 @@ class MeadowSync extends libFableServiceProviderBase
70
70
  this.meadowSchema = pSchema;
71
71
  this.MeadowSchemaTableList = Object.keys(this.meadowSchema.Tables);
72
72
 
73
+ this.log.info(`Loading schema for ${this.MeadowSchemaTableList.length} tables (mode: ${this.SyncMode})`);
74
+
75
+ let tmpEntityIndex = 0;
76
+ let tmpErrorCount = 0;
77
+ let tmpSuccessCount = 0;
78
+
73
79
  this.fable.Utility.eachLimit(this.MeadowSchemaTableList, 1,
74
80
  (pEntitySchemaName, fSyncInitializationComplete) =>
75
81
  {
82
+ tmpEntityIndex++;
76
83
  const tmpEntitySchema = this.meadowSchema.Tables[pEntitySchemaName];
77
84
  // If this is in the entity list or none is specified, create the sync entity object.
78
85
  if (this.SyncEntityList.length < 1 || this.SyncEntityList.indexOf(tmpEntitySchema.TableName) > -1)
@@ -97,7 +104,20 @@ class MeadowSync extends libFableServiceProviderBase
97
104
 
98
105
  this.MeadowSyncEntities[tmpEntitySchema.TableName] = tmpSyncEntity;
99
106
 
100
- return tmpSyncEntity.initialize(fSyncInitializationComplete);
107
+ return tmpSyncEntity.initialize((pInitError) =>
108
+ {
109
+ if (pInitError)
110
+ {
111
+ tmpErrorCount++;
112
+ this.log.warn(`Failed to initialize ${tmpEntitySchema.TableName}: ${pInitError}`);
113
+ }
114
+ else
115
+ {
116
+ tmpSuccessCount++;
117
+ }
118
+ // Always continue to next entity regardless of individual errors
119
+ return fSyncInitializationComplete();
120
+ });
101
121
  }
102
122
  else
103
123
  {
@@ -111,7 +131,7 @@ class MeadowSync extends libFableServiceProviderBase
111
131
  this.log.error(`MeadowSync Error creating sync objects: ${pSyncInitializationError}`, pSyncInitializationError);
112
132
  }
113
133
 
114
- this.log.info('Entity sync objects created!');
134
+ this.log.info(`Entity sync objects created: ${tmpSuccessCount} succeeded, ${tmpErrorCount} failed.`);
115
135
 
116
136
  if (this.SyncEntityList.length < 1)
117
137
  {
@@ -129,7 +149,15 @@ class MeadowSync extends libFableServiceProviderBase
129
149
  this.log.warn(`MeadowSync.syncEntity called for an entity that does not exist: ${pEntityHash}`);
130
150
  return fCallback();
131
151
  }
132
- this.MeadowSyncEntities[pEntityHash].sync(fCallback);
152
+
153
+ this.MeadowSyncEntities[pEntityHash].sync((pError) =>
154
+ {
155
+ if (pError)
156
+ {
157
+ this.log.error(`Sync failed for ${pEntityHash}: ${pError}`);
158
+ }
159
+ return fCallback(pError);
160
+ });
133
161
  }
134
162
 
135
163
  syncAll(fCallback)