@contrail/flexplm 1.8.1-alpha.85853aa → 2.0.0-alpha.df05bb5
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/lib/__tests__/telemetry-test-utils.d.ts +8 -0
- package/lib/__tests__/telemetry-test-utils.js +30 -0
- package/lib/cli/commands/compile.js +17 -7
- package/lib/cli/commands/compile.spec.js +17 -7
- package/lib/cli/commands/create.js +17 -7
- package/lib/cli/commands/create.spec.js +17 -7
- package/lib/cli/commands/upload.js +17 -7
- package/lib/cli/index.js +2 -2
- package/lib/entity-processor/base-entity-processor.d.ts +29 -0
- package/lib/entity-processor/base-entity-processor.js +238 -143
- package/lib/entity-processor/base-entity-processor.spec.js +210 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/publish/base-process-publish-assortment-callback.js +30 -0
- package/lib/publish/base-process-publish-assortment-callback.spec.d.ts +1 -0
- package/lib/publish/base-process-publish-assortment-callback.spec.js +62 -0
- package/lib/publish/base-process-publish-assortment.d.ts +24 -0
- package/lib/publish/base-process-publish-assortment.js +234 -132
- package/lib/publish/base-process-publish-assortment.spec.js +188 -0
- package/lib/util/error-response-object.js +2 -0
- package/lib/util/event-short-message-status.js +1 -1
- package/lib/util/flexplm-connect.d.ts +4 -0
- package/lib/util/flexplm-connect.js +210 -145
- package/lib/util/flexplm-connect.telemetry.spec.d.ts +1 -0
- package/lib/util/flexplm-connect.telemetry.spec.js +212 -0
- package/lib/util/logger-config.js +1 -2
- package/lib/util/telemetry-attributes.d.ts +68 -0
- package/lib/util/telemetry-attributes.js +73 -0
- package/lib/util/telemetry-utils.d.ts +3 -0
- package/lib/util/telemetry-utils.js +10 -0
- package/lib/util/thumbnail-util.d.ts +2 -1
- package/lib/util/thumbnail-util.js +35 -7
- package/lib/util/thumbnail-util.spec.js +42 -0
- package/package.json +10 -3
|
@@ -11,6 +11,12 @@ const fsPromise = require("fs/promises");
|
|
|
11
11
|
const path = require("path");
|
|
12
12
|
const app_framework_1 = require("@contrail/app-framework");
|
|
13
13
|
const event_short_message_status_1 = require("../util/event-short-message-status");
|
|
14
|
+
const telemetry_1 = require("@contrail/telemetry");
|
|
15
|
+
const api_1 = require("@opentelemetry/api");
|
|
16
|
+
const telemetry_attributes_1 = require("../util/telemetry-attributes");
|
|
17
|
+
const telemetry_utils_1 = require("../util/telemetry-utils");
|
|
18
|
+
const PUBLISH_FILE_HYDRATED_DETAIL = 'hydrated_detail';
|
|
19
|
+
const PUBLISH_FILE_BASELINE = 'baseline';
|
|
14
20
|
class BaseProcessPublishAssortment {
|
|
15
21
|
constructor(_config, _dc, _mapFileUtil) {
|
|
16
22
|
this.TTL = 30 * 24 * 60 * 60 * 1000; // 30 days
|
|
@@ -24,61 +30,115 @@ class BaseProcessPublishAssortment {
|
|
|
24
30
|
this.orgSlug = this.config?.orgSlug || 'unset-orgSlug';
|
|
25
31
|
}
|
|
26
32
|
async process(event) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
return (0, telemetry_1.traceSection)('publish_assortment', {}, async (span) => {
|
|
34
|
+
const assortmentPublishChangeId = event.assortmentPublishChangeId;
|
|
35
|
+
let apcHistory;
|
|
36
|
+
let publisher;
|
|
37
|
+
const assortmentId = event.assortmentId;
|
|
38
|
+
(0, telemetry_utils_1.setActiveSpanAttributes)({
|
|
39
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_ASSORTMENT_ID]: assortmentId,
|
|
40
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_CHANGE_ID]: assortmentPublishChangeId,
|
|
41
|
+
});
|
|
35
42
|
try {
|
|
36
|
-
seasonFed
|
|
43
|
+
let seasonFed;
|
|
44
|
+
try {
|
|
45
|
+
seasonFed = await this.getSeasonFederation(assortmentId);
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
const message = e.message;
|
|
49
|
+
const eventStatus = (message.includes(BaseProcessPublishAssortment.ASSORTMENT_NOT_PUBLISHABLE)) ? event_short_message_status_1.EventShortMessageStatus.NOT_PUBLISHABLE :
|
|
50
|
+
(message.startsWith(BaseProcessPublishAssortment.ASSORTMENT_NO_FED_INFO)) ? event_short_message_status_1.EventShortMessageStatus.NO_FEDERATION_INFO :
|
|
51
|
+
event_short_message_status_1.EventShortMessageStatus.FAILURE;
|
|
52
|
+
this.recordPublishStatus({
|
|
53
|
+
status: eventStatus,
|
|
54
|
+
assortmentId,
|
|
55
|
+
assortmentPublishChangeId,
|
|
56
|
+
message,
|
|
57
|
+
// Only an unexpected error is swallowed here; the other two are expected skips.
|
|
58
|
+
error: eventStatus === event_short_message_status_1.EventShortMessageStatus.FAILURE ? e : undefined,
|
|
59
|
+
});
|
|
60
|
+
const output = {
|
|
61
|
+
results: { message, event },
|
|
62
|
+
skip_await: true
|
|
63
|
+
};
|
|
64
|
+
return output;
|
|
65
|
+
}
|
|
66
|
+
apcHistory = await this.getApcHistory(assortmentId);
|
|
67
|
+
const sinceDate = await this.getSinceDate(assortmentId, assortmentPublishChangeId, apcHistory);
|
|
68
|
+
//Get detail information
|
|
69
|
+
const assortmentPublishChange = await this.downloadAssortmentPublishChange(assortmentId, assortmentPublishChangeId);
|
|
70
|
+
publisher = this.getPublisher(assortmentPublishChange);
|
|
71
|
+
const changeDetail = await this.downloadHydratedChangeDetail(assortmentPublishChange);
|
|
72
|
+
// Without the change detail the counts are unknown, not zero; failed_downloads says why.
|
|
73
|
+
if (changeDetail) {
|
|
74
|
+
span.setAttributes({
|
|
75
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_ADDED_COUNT]: changeDetail.adds?.length ?? 0,
|
|
76
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_REMOVED_COUNT]: changeDetail.deletes?.length ?? 0,
|
|
77
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_CHANGED_COUNT]: changeDetail.updates?.length ?? 0,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
const assortmentBaseline = await this.downloadAssortmentBaseline(assortmentPublishChange);
|
|
81
|
+
const failedDownloads = [!changeDetail && PUBLISH_FILE_HYDRATED_DETAIL, !assortmentBaseline && PUBLISH_FILE_BASELINE].filter(Boolean);
|
|
82
|
+
if (failedDownloads.length > 0) {
|
|
83
|
+
span.setAttribute(telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_FAILED_DOWNLOADS, failedDownloads);
|
|
84
|
+
}
|
|
85
|
+
const deleteChanges = await this.getDeleteChanges(assortmentPublishChange, apcHistory, assortmentBaseline, sinceDate);
|
|
86
|
+
const releasedForDevelopmentItemIds = this.getReleasedForDevelopmentItemAndFamilyIds(assortmentBaseline, deleteChanges);
|
|
87
|
+
const itemToFederatedIdMapping = await this.getItemFederatedIds( /*allItemIds*/);
|
|
88
|
+
const pcd = new publish_change_data_1.PublishChangeData(assortmentId, seasonFed, assortmentPublishChangeId, sinceDate, publisher);
|
|
89
|
+
pcd.itemToFederatedIdMapping = itemToFederatedIdMapping;
|
|
90
|
+
pcd.releasedForDevelopmentItemIds = releasedForDevelopmentItemIds;
|
|
91
|
+
const output = await this.processPublish(pcd, changeDetail, assortmentBaseline, deleteChanges);
|
|
92
|
+
output['publishInfo'] = await this.getPublishInfo(assortmentId, assortmentPublishChangeId, apcHistory, publisher);
|
|
93
|
+
return output;
|
|
37
94
|
}
|
|
38
95
|
catch (e) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return output;
|
|
96
|
+
try {
|
|
97
|
+
const publishInfo = await this.getPublishInfo(assortmentId, assortmentPublishChangeId, apcHistory, publisher);
|
|
98
|
+
e.publishInfo = publishInfo;
|
|
99
|
+
}
|
|
100
|
+
catch (e2) {
|
|
101
|
+
telemetry_1.logger.error({ error: e2, assortment: { id: assortmentId, publish_change_id: assortmentPublishChangeId } }, 'getPublishInfo failed');
|
|
102
|
+
}
|
|
103
|
+
this.recordPublishStatus({
|
|
104
|
+
status: event_short_message_status_1.EventShortMessageStatus.FAILURE, assortmentId, assortmentPublishChangeId, error: e,
|
|
105
|
+
// sendAndRecordPublishEvent only sets this after FlexPLM accepted the publish.
|
|
106
|
+
sentUnrecorded: e?.sendPublishPayloadEventResult !== undefined,
|
|
107
|
+
});
|
|
108
|
+
throw e;
|
|
53
109
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
/** Records the result of one assortment publish: attributes on the active span plus one structured log.
|
|
113
|
+
* Not_Publishable / No_Federation_Information are handled skips, so the span stays OK for them.
|
|
114
|
+
*/
|
|
115
|
+
recordPublishStatus(statusObject) {
|
|
116
|
+
const { status, assortmentId, assortmentPublishChangeId, resultsCount, message, error } = statusObject;
|
|
117
|
+
const sentUnrecorded = statusObject.sentUnrecorded || undefined;
|
|
118
|
+
(0, telemetry_utils_1.setActiveSpanAttributes)({
|
|
119
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_STATUS]: status,
|
|
120
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_ASSORTMENT_ID]: assortmentId,
|
|
121
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_CHANGE_ID]: assortmentPublishChangeId,
|
|
122
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_PRODUCT_SEASON_COUNT]: resultsCount?.productSeasons,
|
|
123
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_COLORWAY_SEASON_COUNT]: resultsCount?.colorwaySeasons,
|
|
124
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_SENT_UNRECORDED]: sentUnrecorded,
|
|
125
|
+
});
|
|
126
|
+
const flexplm = {
|
|
127
|
+
direction: 'publish', status, assortment_id: assortmentId, publish_change_id: assortmentPublishChangeId,
|
|
128
|
+
product_season_count: resultsCount?.productSeasons, colorway_season_count: resultsCount?.colorwaySeasons, reason: message,
|
|
129
|
+
sent_unrecorded: sentUnrecorded,
|
|
130
|
+
};
|
|
131
|
+
if (sentUnrecorded) {
|
|
132
|
+
telemetry_1.logger.error({ error, flexplm }, 'FlexPLM assortment publish sent but not recorded');
|
|
71
133
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
console.error('process failed: assortmentId: ' + assortmentId + ': ' + e.message);
|
|
81
|
-
throw e;
|
|
134
|
+
else if (status === event_short_message_status_1.EventShortMessageStatus.FAILURE) {
|
|
135
|
+
telemetry_1.logger.error({ error, flexplm }, 'FlexPLM assortment publish failed');
|
|
136
|
+
}
|
|
137
|
+
else if (status === event_short_message_status_1.EventShortMessageStatus.NO_FEDERATION_INFO) {
|
|
138
|
+
telemetry_1.logger.warn({ flexplm }, 'FlexPLM assortment publish skipped');
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
telemetry_1.logger.info({ flexplm }, 'FlexPLM assortment publish processed');
|
|
82
142
|
}
|
|
83
143
|
}
|
|
84
144
|
async getPublishInfo(assortmentId, assortmentPublishChangeId, apcHistory, publisher) {
|
|
@@ -211,13 +271,18 @@ class BaseProcessPublishAssortment {
|
|
|
211
271
|
return sinceDate;
|
|
212
272
|
}
|
|
213
273
|
async getApcHistory(assortmentId) {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
274
|
+
return (0, telemetry_1.traceSection)('get_publish_history', {}, async (span) => {
|
|
275
|
+
const resource = `/assortments/${assortmentId}/history/`;
|
|
276
|
+
const history = await sdk_1.Request.request(resource, {
|
|
277
|
+
method: 'GET',
|
|
278
|
+
headers: {
|
|
279
|
+
Accept: 'application/json',
|
|
280
|
+
'Content-Type': 'application/json'
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
if (Array.isArray(history))
|
|
284
|
+
span.setAttribute(telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_HISTORY_COUNT, history.length);
|
|
285
|
+
return history;
|
|
221
286
|
});
|
|
222
287
|
}
|
|
223
288
|
updatedSinceDate(entity, sinceDate) {
|
|
@@ -315,30 +380,42 @@ class BaseProcessPublishAssortment {
|
|
|
315
380
|
});
|
|
316
381
|
}
|
|
317
382
|
async downloadHydratedChangeDetail(assortmentPublishChange) {
|
|
318
|
-
|
|
319
|
-
const link = assortmentPublishChange?.hydratedDetailDownloadLink;
|
|
320
|
-
const response = await fetch(link);
|
|
321
|
-
const data = await response.json();
|
|
322
|
-
return data;
|
|
323
|
-
}
|
|
324
|
-
catch (e) {
|
|
325
|
-
console.error('Error hydratedDetailDownloadLink: ' + e.message);
|
|
326
|
-
}
|
|
327
|
-
return undefined;
|
|
383
|
+
return this.downloadPublishFile(assortmentPublishChange?.hydratedDetailDownloadLink, PUBLISH_FILE_HYDRATED_DETAIL);
|
|
328
384
|
}
|
|
329
385
|
async downloadAssortmentBaseline(assortmentPublishChange) {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
386
|
+
return this.downloadPublishFile(assortmentPublishChange?.assortmentBaselineDownloadLink, PUBLISH_FILE_BASELINE);
|
|
387
|
+
}
|
|
388
|
+
/** Downloads one publish file as JSON. Returns undefined when it can't be read, so the publish continues without it;
|
|
389
|
+
* the span is marked ERROR here because nothing is thrown. The link is never recorded (it is a signed URL).
|
|
390
|
+
*/
|
|
391
|
+
async downloadPublishFile(link, file) {
|
|
392
|
+
return (0, telemetry_1.traceSection)('download_publish_file', { [telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_FILE]: file }, async (span) => {
|
|
393
|
+
let httpStatus;
|
|
394
|
+
try {
|
|
395
|
+
const response = await fetch(link);
|
|
396
|
+
httpStatus = response.status;
|
|
397
|
+
span.setAttribute(telemetry_attributes_1.ATTR_HTTP_RESPONSE_STATUS_CODE, httpStatus);
|
|
398
|
+
if (!response.ok) {
|
|
399
|
+
throw new Error('Download failed: status: ' + httpStatus);
|
|
400
|
+
}
|
|
401
|
+
return await response.json();
|
|
402
|
+
}
|
|
403
|
+
catch (e) {
|
|
404
|
+
span.recordException(e);
|
|
405
|
+
span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: e?.message });
|
|
406
|
+
telemetry_1.logger.error({ error: e, flexplm: { direction: 'publish', publish_file: file, http_status: httpStatus } }, 'FlexPLM publish file download failed');
|
|
407
|
+
return undefined;
|
|
408
|
+
}
|
|
409
|
+
});
|
|
340
410
|
}
|
|
341
411
|
async getDeleteChanges(assortmentPublishChange, apcHistory, assortmentBaseline, sinceDate) {
|
|
412
|
+
return (0, telemetry_1.traceSection)('get_delete_changes', {}, async (span) => {
|
|
413
|
+
const deleteChanges = await this.collectDeleteChanges(assortmentPublishChange, apcHistory, assortmentBaseline, sinceDate);
|
|
414
|
+
span.setAttribute(telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_DELETE_CHANGE_COUNT, deleteChanges?.length ?? 0);
|
|
415
|
+
return deleteChanges;
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
async collectDeleteChanges(assortmentPublishChange, apcHistory, assortmentBaseline, sinceDate) {
|
|
342
419
|
const currentAPCIndex = apcHistory.findIndex(pc => pc?.id === assortmentPublishChange?.id);
|
|
343
420
|
if (currentAPCIndex == 0) {
|
|
344
421
|
return [];
|
|
@@ -383,6 +460,7 @@ class BaseProcessPublishAssortment {
|
|
|
383
460
|
console.info('getDeleteChanges(): baselineItems: ' + currentAssortmentItemIds.length
|
|
384
461
|
+ ', scanned ' + scannedCount + ' historical delete changes, added ' + addedCount
|
|
385
462
|
+ ', deleteIds: ' + deleteIds.length);
|
|
463
|
+
(0, telemetry_utils_1.setActiveSpanAttributes)({ [telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_HISTORICAL_DELETE_COUNT]: addedCount });
|
|
386
464
|
console.info('getDeleteChanges()-deleteIds: ' + deleteIds);
|
|
387
465
|
}
|
|
388
466
|
return apcDeletes;
|
|
@@ -559,12 +637,12 @@ class BaseProcessPublishAssortment {
|
|
|
559
637
|
pcd.itemFamilyChanges = this.getItemFamilyChanges(pcd, changeDetail, assortmentItemFullChangeMap, assortmentItemDeleteMap);
|
|
560
638
|
const events = await this.getEventsForPublishChangeData(pcd);
|
|
561
639
|
if (events.length === 0) {
|
|
562
|
-
const processStatus = 'BaseProcessPublishAssortment: ' + event_short_message_status_1.EventShortMessageStatus.NO_EVENTS_TO_SEND
|
|
563
|
-
+ ': assortmentId: ' + pcd.assortmentId + ': assortmentPublishChangeId: ' + pcd.assortmentPublishChangeId
|
|
564
|
-
+ ', orgSlug: ' + this.orgSlug;
|
|
565
|
-
console.log(processStatus);
|
|
566
640
|
const message = 'No Events to Send; returning';
|
|
567
|
-
|
|
641
|
+
this.recordPublishStatus({
|
|
642
|
+
status: event_short_message_status_1.EventShortMessageStatus.NO_EVENTS_TO_SEND,
|
|
643
|
+
assortmentId: pcd.assortmentId,
|
|
644
|
+
assortmentPublishChangeId: pcd.assortmentPublishChangeId,
|
|
645
|
+
});
|
|
568
646
|
return {
|
|
569
647
|
results: { message, event },
|
|
570
648
|
skip_await: true
|
|
@@ -572,11 +650,12 @@ class BaseProcessPublishAssortment {
|
|
|
572
650
|
}
|
|
573
651
|
const results = await this.sendEvents(events);
|
|
574
652
|
const resultsCount = this.getResultsCount(events);
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
653
|
+
this.recordPublishStatus({
|
|
654
|
+
status: event_short_message_status_1.EventShortMessageStatus.SENDING_EVENTS,
|
|
655
|
+
assortmentId: pcd.assortmentId,
|
|
656
|
+
assortmentPublishChangeId: pcd.assortmentPublishChangeId,
|
|
657
|
+
resultsCount,
|
|
658
|
+
});
|
|
580
659
|
return { results, event, resultsCount };
|
|
581
660
|
}
|
|
582
661
|
getResultsCount(events) {
|
|
@@ -595,6 +674,7 @@ class BaseProcessPublishAssortment {
|
|
|
595
674
|
console.info('sendEvents()');
|
|
596
675
|
const eventType = 'ASYNC_PUBLISH_SEASON';
|
|
597
676
|
const sendMode = (this.config?.sendMode[eventType] || '').toLowerCase();
|
|
677
|
+
(0, telemetry_utils_1.setActiveSpanAttributes)({ [telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_SEND_MODE]: sendMode });
|
|
598
678
|
switch (sendMode) {
|
|
599
679
|
case 'sendtoflexplm':
|
|
600
680
|
return this.sendToFlexPLM(events, eventType);
|
|
@@ -604,22 +684,25 @@ class BaseProcessPublishAssortment {
|
|
|
604
684
|
case 'vibeiqfile-dontsendtoflexplm':
|
|
605
685
|
return this.handleVibeIQFile(events, eventType, sendMode);
|
|
606
686
|
default:
|
|
687
|
+
telemetry_1.logger.warn({ flexplm: { direction: 'publish', send_mode: sendMode, payload_count: events?.length ?? 0 } }, 'Unknown FlexPLM publish sendMode; events not sent');
|
|
607
688
|
return {}; // Or handle other cases as required
|
|
608
689
|
}
|
|
609
690
|
}
|
|
610
691
|
async sendToFlexPLM(events, eventType) {
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
692
|
+
return (0, telemetry_1.traceSection)('send_publish_batch', { [telemetry_attributes_1.ATTR_FLEXPLM_PAYLOAD_COUNT]: events?.length ?? 0 }, async () => {
|
|
693
|
+
const outboundPublishEvent = {
|
|
694
|
+
taskId: this.config.taskId,
|
|
695
|
+
eventType,
|
|
696
|
+
objectClass: 'LCSSeason',
|
|
697
|
+
events
|
|
698
|
+
};
|
|
699
|
+
const flexPLMConnect = new flexplm_connect_1.FlexPLMConnect(this.config);
|
|
700
|
+
const result = await this.sendAndRecordPublishEvent(flexPLMConnect, outboundPublishEvent);
|
|
701
|
+
const isResultObject = typeof result === 'object' && result !== null;
|
|
702
|
+
return isResultObject
|
|
703
|
+
? { ...result, outboundPublishEvent }
|
|
704
|
+
: { result, outboundPublishEvent };
|
|
705
|
+
});
|
|
623
706
|
}
|
|
624
707
|
async sendAndRecordPublishEvent(flexPLMConnect, outboundPublishEvent) {
|
|
625
708
|
let sendResult;
|
|
@@ -668,6 +751,7 @@ class BaseProcessPublishAssortment {
|
|
|
668
751
|
};
|
|
669
752
|
}
|
|
670
753
|
catch (e) {
|
|
754
|
+
telemetry_1.logger.error({ error: e, flexplm: { direction: 'publish', send_mode: 'localfile' } }, 'Saving FlexPLM publish events to a local file failed');
|
|
671
755
|
results['error'] = e.message;
|
|
672
756
|
}
|
|
673
757
|
finally {
|
|
@@ -678,7 +762,7 @@ class BaseProcessPublishAssortment {
|
|
|
678
762
|
async handleVibeIQFile(events, eventType, sendMode) {
|
|
679
763
|
const eventBuffer = Buffer.from(JSON.stringify(events), 'utf-8');
|
|
680
764
|
const fileName = 'ASYNC_PUBLISH_SEASON-events.json';
|
|
681
|
-
const uploadFile = await new sdk_1.Files().createAndUploadFileFromBuffer(eventBuffer, 'application/json', fileName, null, this.TTL);
|
|
765
|
+
const uploadFile = await (0, telemetry_1.traceSection)('upload_publish_events_file', { [telemetry_attributes_1.ATTR_FLEXPLM_PAYLOAD_COUNT]: events?.length ?? 0 }, () => new sdk_1.Files().createAndUploadFileFromBuffer(eventBuffer, 'application/json', fileName, null, this.TTL));
|
|
682
766
|
const outboundPublishEvent = {
|
|
683
767
|
taskId: this.config.taskId,
|
|
684
768
|
eventType,
|
|
@@ -688,12 +772,14 @@ class BaseProcessPublishAssortment {
|
|
|
688
772
|
eventsAdminDownloadLink: uploadFile.adminDownloadUrl
|
|
689
773
|
};
|
|
690
774
|
if (sendMode === 'vibeiqfile') {
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
775
|
+
return (0, telemetry_1.traceSection)('send_publish_batch', { [telemetry_attributes_1.ATTR_FLEXPLM_PAYLOAD_COUNT]: events?.length ?? 0 }, async () => {
|
|
776
|
+
const flexPLMConnect = new flexplm_connect_1.FlexPLMConnect(this.config);
|
|
777
|
+
const result = await this.sendAndRecordPublishEvent(flexPLMConnect, outboundPublishEvent);
|
|
778
|
+
const isResultObject = typeof result === 'object' && result !== null;
|
|
779
|
+
return isResultObject
|
|
780
|
+
? { ...result, outboundPublishEvent }
|
|
781
|
+
: { result, outboundPublishEvent };
|
|
782
|
+
});
|
|
697
783
|
}
|
|
698
784
|
else {
|
|
699
785
|
await this.sendPublishPayloadEvent(outboundPublishEvent);
|
|
@@ -704,22 +790,24 @@ class BaseProcessPublishAssortment {
|
|
|
704
790
|
}
|
|
705
791
|
}
|
|
706
792
|
async sendPublishPayloadEvent(outboundPublishEvent) {
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
793
|
+
return (0, telemetry_1.traceSection)('record_publish_event', {}, async () => {
|
|
794
|
+
console.info('sendPublishPayloadEvent()');
|
|
795
|
+
let initialEvent = {};
|
|
796
|
+
if (this.config?.event) {
|
|
797
|
+
initialEvent = (typeof this.config?.event === 'string')
|
|
798
|
+
? JSON.parse(this.config?.event)
|
|
799
|
+
: this.config?.event;
|
|
800
|
+
}
|
|
801
|
+
const eventBody = {
|
|
802
|
+
originSystemType: 'VibeIQ',
|
|
803
|
+
objectClass: 'AssortmentPublishedToFlexPLM',
|
|
804
|
+
outboundPublishEvent,
|
|
805
|
+
initialEvent
|
|
806
|
+
};
|
|
807
|
+
await new sdk_1.Entities().create({
|
|
808
|
+
entityName: 'external-event',
|
|
809
|
+
object: eventBody
|
|
810
|
+
});
|
|
723
811
|
});
|
|
724
812
|
}
|
|
725
813
|
getCurrentDateString() {
|
|
@@ -812,6 +900,7 @@ class BaseProcessPublishAssortment {
|
|
|
812
900
|
}
|
|
813
901
|
}
|
|
814
902
|
}
|
|
903
|
+
const skippedDeletes = [];
|
|
815
904
|
for (const [itemId, delEntity] of assortmentItemDeleteMap) {
|
|
816
905
|
const itemFamilyId = delEntity?.item?.itemFamilyId;
|
|
817
906
|
const item = delEntity?.item;
|
|
@@ -823,7 +912,7 @@ class BaseProcessPublishAssortment {
|
|
|
823
912
|
}
|
|
824
913
|
else {
|
|
825
914
|
if (!item) {
|
|
826
|
-
|
|
915
|
+
skippedDeletes.push({ item_family_id: itemFamilyId, item_id: itemId });
|
|
827
916
|
continue;
|
|
828
917
|
}
|
|
829
918
|
}
|
|
@@ -855,6 +944,14 @@ class BaseProcessPublishAssortment {
|
|
|
855
944
|
ifc.colorDeletes.push(itemId);
|
|
856
945
|
}
|
|
857
946
|
} //End deletes for loop
|
|
947
|
+
if (skippedDeletes.length > 0) {
|
|
948
|
+
// These deletes are not sent to FlexPLM; one warning for the publish rather than one per item.
|
|
949
|
+
(0, telemetry_utils_1.setActiveSpanAttributes)({ [telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_SKIPPED_DELETE_COUNT]: skippedDeletes.length });
|
|
950
|
+
telemetry_1.logger.warn({ flexplm: {
|
|
951
|
+
direction: 'publish', assortment_id: pcd.assortmentId, publish_change_id: pcd.assortmentPublishChangeId,
|
|
952
|
+
skipped_delete_count: skippedDeletes.length, skipped_deletes: skippedDeletes,
|
|
953
|
+
} }, 'FlexPLM publish skipped deleted items with no item entity');
|
|
954
|
+
}
|
|
858
955
|
if (app_framework_1.Logger.isDebugOn()) {
|
|
859
956
|
console.debug('returning size: ' + itemFamilyChanges.size);
|
|
860
957
|
for (const [key, value] of itemFamilyChanges) {
|
|
@@ -864,16 +961,21 @@ class BaseProcessPublishAssortment {
|
|
|
864
961
|
return itemFamilyChanges;
|
|
865
962
|
}
|
|
866
963
|
async getEventsForPublishChangeData(publishChangeData) {
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
964
|
+
return (0, telemetry_1.traceSection)('build_publish_events', {
|
|
965
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_ITEM_FAMILY_COUNT]: publishChangeData.itemFamilyChanges?.size ?? 0,
|
|
966
|
+
}, async (span) => {
|
|
967
|
+
const seasonalPayloads = [];
|
|
968
|
+
for (const itemFamilyChange of publishChangeData.itemFamilyChanges.values()) {
|
|
969
|
+
const events = await this.getEventsForItemFamilyChanges(itemFamilyChange, publishChangeData.assortmentId, publishChangeData.seasonFed, publishChangeData.itemToFederatedIdMapping);
|
|
970
|
+
if (events.length > 0) {
|
|
971
|
+
seasonalPayloads.push(...events);
|
|
972
|
+
}
|
|
872
973
|
}
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
974
|
+
console.info('getEventsForPublishChangeData: itemFamilies: '
|
|
975
|
+
+ publishChangeData.itemFamilyChanges.size + ', payloads: ' + seasonalPayloads.length);
|
|
976
|
+
span.setAttribute(telemetry_attributes_1.ATTR_FLEXPLM_PAYLOAD_COUNT, seasonalPayloads.length);
|
|
977
|
+
return seasonalPayloads;
|
|
978
|
+
});
|
|
877
979
|
}
|
|
878
980
|
/**Returns the events for a given ItemFamilyChanges object
|
|
879
981
|
*
|