@amplience/dc-cli
Version:
Dynamic Content CLI Tool
137 lines (136 loc) • 5.39 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PublishQueue = exports.delay = exports.DEFAULT_PUBLISH_RATE_LIMIT = exports.MAX_PUBLISH_RATE_LIMIT = void 0;
const dc_management_sdk_js_1 = require("dc-management-sdk-js");
const node_fetch_1 = __importDefault(require("node-fetch"));
exports.MAX_PUBLISH_RATE_LIMIT = 80;
exports.DEFAULT_PUBLISH_RATE_LIMIT = 35;
const delay = (duration) => {
return new Promise((resolve) => {
setTimeout(resolve, duration);
});
};
exports.delay = delay;
class PublishQueue {
constructor(config) {
this.maxWaiting = 35;
this.maxAttempts = 30;
this.attemptDelay = 1000;
this.attemptRateLimit = 60000 / 35;
this.failedJobs = [];
this.unresolvedJobs = [];
this.inProgressJobs = [];
this.waitingList = [];
this.delayUntil = [];
this.delayId = 0;
this.waitInProgress = false;
const http = new dc_management_sdk_js_1.AxiosHttpClient({});
if (config.clientId && config.clientSecret) {
this.auth = new dc_management_sdk_js_1.Oauth2AuthHeaderProvider({ client_id: config.clientId, client_secret: config.clientSecret }, { authUrl: process.env.AUTH_URL || 'https://auth.amplience.net' }, http);
}
else if (config.patToken) {
this.auth = new dc_management_sdk_js_1.PatTokenAuthHeaderProvider(config.patToken);
}
const publishRateLimit = Math.min((config === null || config === void 0 ? void 0 : config.publishRateLimit) || exports.DEFAULT_PUBLISH_RATE_LIMIT, exports.MAX_PUBLISH_RATE_LIMIT);
this.attemptRateLimit = 60000 / publishRateLimit;
}
async fetch(href, method) {
return await (0, node_fetch_1.default)(href, { method: method, headers: { Authorization: await this.auth.getAuthHeader() } });
}
async publish(item) {
await this.rateLimit();
const publishLink = item._links['publish'];
if (publishLink == null) {
throw new Error('Cannot publish the item - link not available.');
}
const publish = await this.fetch(publishLink.href, 'POST');
if (publish.status != 204) {
throw new Error(`Failed to start publish: ${publish.statusText} - ${await publish.text()}`);
}
const publishJobInfoHref = publish.headers.get('Location');
if (publishJobInfoHref == null) {
throw new Error('Expected publish job location in header. Has the publish workflow changed?');
}
this.inProgressJobs.push({ href: publishJobInfoHref, item });
}
async waitForOldestPublish() {
if (this.inProgressJobs.length === 0) {
return;
}
this.waitInProgress = true;
const oldestJob = this.inProgressJobs[0];
this.inProgressJobs.splice(0, 1);
let attempts = 0;
for (; attempts < this.maxAttempts; attempts++) {
let job;
try {
job = await (await this.fetch(oldestJob.href, 'GET')).json();
}
catch (e) {
continue;
}
if (job.state === 'COMPLETED') {
break;
}
else if (job.state === 'FAILED') {
this.failedJobs.push(oldestJob);
break;
}
else {
await (0, exports.delay)(this.attemptDelay);
}
}
if (attempts == this.maxAttempts) {
this.unresolvedJobs.push(oldestJob);
}
const oldestWaiter = this.waitingList[0];
if (oldestWaiter != null) {
this.waitingList.splice(0, 1);
oldestWaiter.resolver();
}
if (this.waitingList.length > 0 || this.awaitingAll) {
await this.waitForOldestPublish();
}
else {
this.waitInProgress = false;
}
}
async rateLimit() {
const now = Date.now();
if (now < this.delayUntil[this.delayId] || 0) {
await (0, exports.delay)(this.delayUntil[this.delayId] - now);
}
this.delayUntil[this.delayId] = now + this.attemptRateLimit * this.maxWaiting;
this.delayId = (this.delayId + 1) % this.maxWaiting;
if (this.inProgressJobs.length != this.maxWaiting) {
return;
}
let resolver = () => {
};
const myPromise = new Promise((resolve) => {
resolver = resolve;
});
this.waitingList.push({ promise: myPromise, resolver: resolver });
if (!this.waitInProgress) {
this.waitForOldestPublish();
}
await myPromise;
}
async waitForAll() {
var _a;
if (this.waitInProgress) {
await ((_a = this.waitingList[this.waitingList.length - 1]) === null || _a === void 0 ? void 0 : _a.promise);
}
this.inProgressJobs = [...this.inProgressJobs, ...this.unresolvedJobs];
this.unresolvedJobs = [];
this.awaitingAll = true;
await this.waitForOldestPublish();
}
isEmpty() {
return this.inProgressJobs.length === 0 && this.unresolvedJobs.length === 0;
}
}
exports.PublishQueue = PublishQueue;