@speedkit/cli 2.22.0 → 2.23.0
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/CHANGELOG.md +11 -0
- package/README.md +12 -34
- package/dist/commands/prewarm.d.ts +5 -26
- package/dist/commands/prewarm.js +23 -103
- package/dist/models/cli-parameters.d.ts +4 -1
- package/dist/models/cli-parameters.js +3 -0
- package/dist/services/cli/cli-service-factory.d.ts +3 -0
- package/dist/services/cli/cli-service-factory.js +9 -1
- package/dist/services/cli/cli-service-model.d.ts +19 -11
- package/dist/services/cli/cli-service-model.js +8 -1
- package/dist/services/cli/cli-service.d.ts +20 -13
- package/dist/services/cli/cli-service.js +102 -66
- package/dist/services/config-api/client.d.ts +7 -9
- package/dist/services/config-api/client.js +26 -30
- package/dist/services/prewarm/assets/asset-api-client.d.ts +13 -0
- package/dist/services/prewarm/assets/asset-api-client.js +58 -0
- package/dist/services/prewarm/assets/asset-item.d.ts +14 -0
- package/dist/services/prewarm/assets/asset-item.js +29 -0
- package/dist/services/prewarm/assets/asset-list.d.ts +14 -0
- package/dist/services/prewarm/assets/asset-list.js +43 -0
- package/dist/services/prewarm/csv-reader.d.ts +5 -0
- package/dist/services/prewarm/csv-reader.js +34 -0
- package/dist/services/prewarm/error/invalid-origin-error.d.ts +2 -0
- package/dist/services/prewarm/error/invalid-origin-error.js +6 -0
- package/dist/services/prewarm/error/read-csv-error.d.ts +8 -0
- package/dist/services/prewarm/error/read-csv-error.js +18 -0
- package/dist/services/prewarm/index.d.ts +3 -0
- package/dist/services/prewarm/index.js +6 -0
- package/dist/services/prewarm/pre-warm-factory.d.ts +8 -0
- package/dist/services/prewarm/pre-warm-factory.js +40 -0
- package/dist/services/prewarm/pre-warm-model.d.ts +38 -0
- package/dist/services/prewarm/pre-warm-model.js +38 -0
- package/dist/services/prewarm/pre-warm-service.d.ts +21 -0
- package/dist/services/prewarm/pre-warm-service.js +154 -0
- package/oclif.manifest.json +24 -63
- package/package.json +1 -1
- package/dist/commands/pop-prewarm.d.ts +0 -17
- package/dist/commands/pop-prewarm.js +0 -90
- package/dist/services/cli/hooks.d.ts +0 -11
- package/dist/services/cli/hooks.js +0 -33
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { AssetApiClient } from "./assets/asset-api-client";
|
|
2
|
+
export declare class PreWarmContext {
|
|
3
|
+
readonly app: string;
|
|
4
|
+
readonly path: string;
|
|
5
|
+
readonly variation?: string;
|
|
6
|
+
readonly variationPath?: string;
|
|
7
|
+
readonly keepParameterSorting: boolean;
|
|
8
|
+
readonly quiet: boolean;
|
|
9
|
+
constructor(app: string, path: string, variation?: string, variationPath?: string, keepParameterSorting?: boolean, quiet?: boolean);
|
|
10
|
+
}
|
|
11
|
+
export interface AssetItemInterface {
|
|
12
|
+
callback: (client: AssetApiClient, entry: AssetItemInterface) => Promise<void>;
|
|
13
|
+
done(): void;
|
|
14
|
+
error?: Error;
|
|
15
|
+
failed(): void;
|
|
16
|
+
retry(): void;
|
|
17
|
+
setError(error: Error): void;
|
|
18
|
+
status: ItemStatus;
|
|
19
|
+
url: string;
|
|
20
|
+
variation: string;
|
|
21
|
+
}
|
|
22
|
+
export declare enum ItemStatus {
|
|
23
|
+
DONE = "done",
|
|
24
|
+
ERROR = "error",
|
|
25
|
+
NEW = "new",
|
|
26
|
+
RETRY = "retry"
|
|
27
|
+
}
|
|
28
|
+
export declare const MIN_TIME_TO_FETCH_BATCH = 1000;
|
|
29
|
+
export declare const FETCH_TIMEOUT = 10000;
|
|
30
|
+
export declare const TIMOUT_AFTER_DETECTED_RATE_LIMIT = 5000;
|
|
31
|
+
export declare const DEFAULT_MAX_REQUESTS_PER_SECOND = 15;
|
|
32
|
+
export declare const RATE_LIMIT_MULTIPLICATOR = 0.8;
|
|
33
|
+
export declare const RATE_LIMIT_CODES: string[];
|
|
34
|
+
export declare const TIMING_HEADER_ERROR_CODE_SELECTOR: RegExp;
|
|
35
|
+
export declare const TIMING_HEADER_KEY = "server-timing";
|
|
36
|
+
export declare const PROGRESS_BAR_FORMAT = "[{bar}] {percentage}% | ETA: {eta}s | {value}/{total} | error:{errors} | rate: {rate} | retry: {retry}";
|
|
37
|
+
export declare const VARIATION_SEPARATOR = ",";
|
|
38
|
+
export declare const DEFAULT_VARIATION: string[];
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_VARIATION = exports.VARIATION_SEPARATOR = exports.PROGRESS_BAR_FORMAT = exports.TIMING_HEADER_KEY = exports.TIMING_HEADER_ERROR_CODE_SELECTOR = exports.RATE_LIMIT_CODES = exports.RATE_LIMIT_MULTIPLICATOR = exports.DEFAULT_MAX_REQUESTS_PER_SECOND = exports.TIMOUT_AFTER_DETECTED_RATE_LIMIT = exports.FETCH_TIMEOUT = exports.MIN_TIME_TO_FETCH_BATCH = exports.ItemStatus = exports.PreWarmContext = void 0;
|
|
4
|
+
class PreWarmContext {
|
|
5
|
+
app;
|
|
6
|
+
path;
|
|
7
|
+
variation;
|
|
8
|
+
variationPath;
|
|
9
|
+
keepParameterSorting;
|
|
10
|
+
quiet;
|
|
11
|
+
constructor(app, path, variation, variationPath, keepParameterSorting = true, quiet = false) {
|
|
12
|
+
this.app = app;
|
|
13
|
+
this.path = path;
|
|
14
|
+
this.variation = variation;
|
|
15
|
+
this.variationPath = variationPath;
|
|
16
|
+
this.keepParameterSorting = keepParameterSorting;
|
|
17
|
+
this.quiet = quiet;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.PreWarmContext = PreWarmContext;
|
|
21
|
+
var ItemStatus;
|
|
22
|
+
(function (ItemStatus) {
|
|
23
|
+
ItemStatus["DONE"] = "done";
|
|
24
|
+
ItemStatus["ERROR"] = "error";
|
|
25
|
+
ItemStatus["NEW"] = "new";
|
|
26
|
+
ItemStatus["RETRY"] = "retry";
|
|
27
|
+
})(ItemStatus || (exports.ItemStatus = ItemStatus = {}));
|
|
28
|
+
exports.MIN_TIME_TO_FETCH_BATCH = 1000;
|
|
29
|
+
exports.FETCH_TIMEOUT = 10_000;
|
|
30
|
+
exports.TIMOUT_AFTER_DETECTED_RATE_LIMIT = 5000;
|
|
31
|
+
exports.DEFAULT_MAX_REQUESTS_PER_SECOND = 15;
|
|
32
|
+
exports.RATE_LIMIT_MULTIPLICATOR = 0.8;
|
|
33
|
+
exports.RATE_LIMIT_CODES = ["308", "310", "316"];
|
|
34
|
+
exports.TIMING_HEADER_ERROR_CODE_SELECTOR = /errorcode;desc=([^,]*),/;
|
|
35
|
+
exports.TIMING_HEADER_KEY = "server-timing";
|
|
36
|
+
exports.PROGRESS_BAR_FORMAT = "[{bar}] {percentage}% | ETA: {eta}s | {value}/{total} | error:{errors} | rate: {rate} | retry: {retry}";
|
|
37
|
+
exports.VARIATION_SEPARATOR = ",";
|
|
38
|
+
exports.DEFAULT_VARIATION = ["DEFAULT"];
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { CliServiceInterface } from "../cli";
|
|
2
|
+
import { AssetItemInterface } from "./";
|
|
3
|
+
import { AssetApiClient } from "./assets/asset-api-client";
|
|
4
|
+
export declare class PreWarmService {
|
|
5
|
+
private assetClient;
|
|
6
|
+
private cli;
|
|
7
|
+
private urls;
|
|
8
|
+
private variations;
|
|
9
|
+
constructor(assetClient: AssetApiClient, cli: CliServiceInterface, urls: string[], variations: string[]);
|
|
10
|
+
handleRequestCallback(assetClient: AssetApiClient, entry: AssetItemInterface): Promise<void>;
|
|
11
|
+
run(): Promise<void>;
|
|
12
|
+
private fetchBatch;
|
|
13
|
+
private fetchUrls;
|
|
14
|
+
private generateAssetRequestList;
|
|
15
|
+
private printSummary;
|
|
16
|
+
private sleep;
|
|
17
|
+
private startProgressBar;
|
|
18
|
+
private stopProgressBar;
|
|
19
|
+
private updateProgressBar;
|
|
20
|
+
private updateRateLimit;
|
|
21
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PreWarmService = void 0;
|
|
4
|
+
const safe_1 = require("../../helpers/safe");
|
|
5
|
+
const _1 = require("./");
|
|
6
|
+
const asset_item_1 = require("./assets/asset-item");
|
|
7
|
+
const asset_list_1 = require("./assets/asset-list");
|
|
8
|
+
class PreWarmService {
|
|
9
|
+
assetClient;
|
|
10
|
+
cli;
|
|
11
|
+
urls;
|
|
12
|
+
variations;
|
|
13
|
+
constructor(assetClient, cli, urls, variations) {
|
|
14
|
+
this.assetClient = assetClient;
|
|
15
|
+
this.cli = cli;
|
|
16
|
+
this.urls = urls;
|
|
17
|
+
this.variations = variations;
|
|
18
|
+
}
|
|
19
|
+
async handleRequestCallback(assetClient, entry) {
|
|
20
|
+
const fetchUrlResponse = await (0, safe_1.safe)(assetClient.fetchURL(entry.url, entry.variation));
|
|
21
|
+
// a generic error occurred
|
|
22
|
+
if (fetchUrlResponse.success === false) {
|
|
23
|
+
entry.failed();
|
|
24
|
+
entry.setError(fetchUrlResponse.errorObj);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const response = fetchUrlResponse.data;
|
|
28
|
+
// success
|
|
29
|
+
if (response.status === 200) {
|
|
30
|
+
entry.done();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
// got undefined errorCode
|
|
34
|
+
if (!response.headers.has(_1.TIMING_HEADER_KEY) ||
|
|
35
|
+
!response.headers.get(_1.TIMING_HEADER_KEY)?.includes("error")) {
|
|
36
|
+
entry.failed();
|
|
37
|
+
entry.setError(new Error(`status: ${response.status}`));
|
|
38
|
+
}
|
|
39
|
+
// get errorCode from server-timing-header
|
|
40
|
+
const serverTiming = response.headers.get(_1.TIMING_HEADER_KEY);
|
|
41
|
+
const [, serverTimingErrorCode] = serverTiming.match(_1.TIMING_HEADER_ERROR_CODE_SELECTOR) || ["", "-"];
|
|
42
|
+
// rateLimiter detected, retry
|
|
43
|
+
if (_1.RATE_LIMIT_CODES.some((code) => serverTimingErrorCode.includes(code))) {
|
|
44
|
+
entry.retry();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
// other errorCode detected
|
|
48
|
+
entry.failed();
|
|
49
|
+
entry.setError(new Error(`status: ${response.status}, sk-error: ${serverTimingErrorCode}`));
|
|
50
|
+
}
|
|
51
|
+
async run() {
|
|
52
|
+
const assetList = this.generateAssetRequestList(this.urls);
|
|
53
|
+
await this.fetchUrls(assetList);
|
|
54
|
+
await this.printSummary(assetList);
|
|
55
|
+
if (assetList.getRetryCount() === 0) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
this.cli.write("Retry rateLimited requests.");
|
|
59
|
+
const urlsToRetry = assetList
|
|
60
|
+
.getByStatus(_1.ItemStatus.RETRY)
|
|
61
|
+
.map((entry) => entry.url);
|
|
62
|
+
const retryList = this.generateAssetRequestList(urlsToRetry);
|
|
63
|
+
await this.fetchUrls(retryList);
|
|
64
|
+
await this.printSummary(retryList);
|
|
65
|
+
}
|
|
66
|
+
async fetchBatch(assetList, offset) {
|
|
67
|
+
// get batch in size of current rateLimit
|
|
68
|
+
const batch = assetList.getBatch(offset, this.assetClient.getRateLimit());
|
|
69
|
+
if (batch.length <= 0) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
await Promise.all([
|
|
73
|
+
...batch.map((entry) => {
|
|
74
|
+
return entry.callback(this.assetClient, entry);
|
|
75
|
+
}),
|
|
76
|
+
// one batch must take at least on second to run
|
|
77
|
+
this.sleep(_1.MIN_TIME_TO_FETCH_BATCH),
|
|
78
|
+
]);
|
|
79
|
+
// update offset for next batch
|
|
80
|
+
offset += batch.length;
|
|
81
|
+
this.updateProgressBar(offset, assetList);
|
|
82
|
+
await this.updateRateLimit(batch);
|
|
83
|
+
// fetch next batch
|
|
84
|
+
await this.fetchBatch(assetList, offset);
|
|
85
|
+
}
|
|
86
|
+
async fetchUrls(assetList) {
|
|
87
|
+
this.cli.write(`start prewarm ${assetList.getLength()} assets`);
|
|
88
|
+
this.startProgressBar(assetList);
|
|
89
|
+
await this.fetchBatch(assetList, 0);
|
|
90
|
+
this.stopProgressBar();
|
|
91
|
+
}
|
|
92
|
+
generateAssetRequestList(urls) {
|
|
93
|
+
const assetList = new asset_list_1.AssetList(this.variations);
|
|
94
|
+
for (const variation of this.variations) {
|
|
95
|
+
for (const url of urls)
|
|
96
|
+
assetList.addItem(new asset_item_1.AssetItem(url, variation, this.handleRequestCallback));
|
|
97
|
+
}
|
|
98
|
+
return assetList;
|
|
99
|
+
}
|
|
100
|
+
async printSummary(assetList) {
|
|
101
|
+
const successCount = assetList.getSuccessCount();
|
|
102
|
+
const errorCount = assetList.getErrorCount();
|
|
103
|
+
const rateLimitCount = assetList.getRetryCount();
|
|
104
|
+
this.cli.table([{ error: errorCount, retry: rateLimitCount, succeed: successCount }], {
|
|
105
|
+
error: {},
|
|
106
|
+
retry: {},
|
|
107
|
+
succeed: {},
|
|
108
|
+
});
|
|
109
|
+
if (await this.cli.confirm("show errors?", true)) {
|
|
110
|
+
const elements = assetList.getByStatus(_1.ItemStatus.ERROR);
|
|
111
|
+
this.cli.table(elements.map((element) => {
|
|
112
|
+
return { ...element };
|
|
113
|
+
}), {
|
|
114
|
+
error: {
|
|
115
|
+
get(row) {
|
|
116
|
+
return row.error.message;
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
url: {},
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
async sleep(ms) {
|
|
124
|
+
return new Promise((resolve) => {
|
|
125
|
+
setTimeout(resolve, ms);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
startProgressBar(assetList) {
|
|
129
|
+
this.cli.startProgress(assetList.getLength(), 0, {
|
|
130
|
+
errors: 0,
|
|
131
|
+
rate: this.assetClient.getRateLimit(),
|
|
132
|
+
retry: 0,
|
|
133
|
+
}, { format: _1.PROGRESS_BAR_FORMAT });
|
|
134
|
+
}
|
|
135
|
+
stopProgressBar() {
|
|
136
|
+
this.cli.stopProgress();
|
|
137
|
+
}
|
|
138
|
+
updateProgressBar(offset, assetList) {
|
|
139
|
+
this.cli.updateProgress(offset, {
|
|
140
|
+
errors: assetList.getErrorCount(),
|
|
141
|
+
rate: this.assetClient.getRateLimit(),
|
|
142
|
+
retry: assetList.getRetryCount(),
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
async updateRateLimit(batch) {
|
|
146
|
+
const retryCount = batch.filter((entry) => entry.status === _1.ItemStatus.RETRY).length;
|
|
147
|
+
// found rateLimiterResponse wait and reduce rateLimit
|
|
148
|
+
if (retryCount > 0) {
|
|
149
|
+
await this.sleep(_1.TIMOUT_AFTER_DETECTED_RATE_LIMIT);
|
|
150
|
+
this.assetClient.reduceMaxRequestsPerSecond();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
exports.PreWarmService = PreWarmService;
|
package/oclif.manifest.json
CHANGED
|
@@ -476,54 +476,6 @@
|
|
|
476
476
|
"onboarding.js"
|
|
477
477
|
]
|
|
478
478
|
},
|
|
479
|
-
"pop-prewarm": {
|
|
480
|
-
"aliases": [],
|
|
481
|
-
"args": {
|
|
482
|
-
"app": {
|
|
483
|
-
"description": "The customers appName",
|
|
484
|
-
"hidden": false,
|
|
485
|
-
"name": "app",
|
|
486
|
-
"required": true
|
|
487
|
-
}
|
|
488
|
-
},
|
|
489
|
-
"description": "Pre-warm Fastly PoPs",
|
|
490
|
-
"examples": [
|
|
491
|
-
"$ sk pop-prewarm <app> -c <contentTypes> -i <ips>",
|
|
492
|
-
"$ sk pop-prewarm decathlon -c image,style -i 151.101.120.194"
|
|
493
|
-
],
|
|
494
|
-
"flags": {
|
|
495
|
-
"ips": {
|
|
496
|
-
"char": "i",
|
|
497
|
-
"name": "ips",
|
|
498
|
-
"default": "151.101.120.194",
|
|
499
|
-
"hasDynamicHelp": false,
|
|
500
|
-
"multiple": false,
|
|
501
|
-
"type": "option"
|
|
502
|
-
},
|
|
503
|
-
"contentTypes": {
|
|
504
|
-
"char": "c",
|
|
505
|
-
"name": "contentTypes",
|
|
506
|
-
"default": "image",
|
|
507
|
-
"hasDynamicHelp": false,
|
|
508
|
-
"multiple": false,
|
|
509
|
-
"type": "option"
|
|
510
|
-
}
|
|
511
|
-
},
|
|
512
|
-
"hasDynamicHelp": false,
|
|
513
|
-
"hiddenAliases": [],
|
|
514
|
-
"id": "pop-prewarm",
|
|
515
|
-
"pluginAlias": "@speedkit/cli",
|
|
516
|
-
"pluginName": "@speedkit/cli",
|
|
517
|
-
"pluginType": "core",
|
|
518
|
-
"strict": true,
|
|
519
|
-
"enableJsonFlag": false,
|
|
520
|
-
"isESM": false,
|
|
521
|
-
"relativePath": [
|
|
522
|
-
"dist",
|
|
523
|
-
"commands",
|
|
524
|
-
"pop-prewarm.js"
|
|
525
|
-
]
|
|
526
|
-
},
|
|
527
479
|
"prewarm": {
|
|
528
480
|
"aliases": [],
|
|
529
481
|
"args": {
|
|
@@ -533,7 +485,7 @@
|
|
|
533
485
|
"required": true
|
|
534
486
|
},
|
|
535
487
|
"path": {
|
|
536
|
-
"description": "path to prewarmFile",
|
|
488
|
+
"description": "path to prewarmFile.csv",
|
|
537
489
|
"name": "path",
|
|
538
490
|
"required": true
|
|
539
491
|
}
|
|
@@ -541,12 +493,13 @@
|
|
|
541
493
|
"description": "Pre-warm Fastly",
|
|
542
494
|
"examples": [
|
|
543
495
|
"for a single variation:",
|
|
544
|
-
"$ sk prewarm <app> <path> -v <variation> -
|
|
545
|
-
"$ sk prewarm decathlon C:\\Users\\testUser\\file.csv -v MOBILE -
|
|
496
|
+
"$ sk prewarm <app> <path> -v <variation> -k",
|
|
497
|
+
"$ sk prewarm decathlon C:\\Users\\testUser\\file.csv -v MOBILE -k",
|
|
546
498
|
"",
|
|
547
499
|
"for a list of variations:",
|
|
548
|
-
"$ sk prewarm <app> <path> -p <variationPath> -
|
|
549
|
-
"$ sk prewarm decathlon C:\\Users\\testUser\\file.csv -
|
|
500
|
+
"$ sk prewarm <app> <path> -p <variationPath> -k",
|
|
501
|
+
"$ sk prewarm decathlon C:\\Users\\testUser\\file.csv -v MOBILE,DESKTOP -k",
|
|
502
|
+
"$ sk prewarm decathlon C:\\Users\\testUser\\file.csv -p C:\\Users\\testUser\\variations.csv -k"
|
|
550
503
|
],
|
|
551
504
|
"flags": {
|
|
552
505
|
"variation": {
|
|
@@ -559,6 +512,7 @@
|
|
|
559
512
|
},
|
|
560
513
|
"variationPath": {
|
|
561
514
|
"char": "p",
|
|
515
|
+
"description": "path to variations.csv",
|
|
562
516
|
"exclusive": [
|
|
563
517
|
"variation"
|
|
564
518
|
],
|
|
@@ -567,21 +521,28 @@
|
|
|
567
521
|
"multiple": false,
|
|
568
522
|
"type": "option"
|
|
569
523
|
},
|
|
570
|
-
"delay": {
|
|
571
|
-
"char": "d",
|
|
572
|
-
"description": "Request delay in ms",
|
|
573
|
-
"name": "delay",
|
|
574
|
-
"default": 0,
|
|
575
|
-
"hasDynamicHelp": false,
|
|
576
|
-
"multiple": false,
|
|
577
|
-
"type": "option"
|
|
578
|
-
},
|
|
579
524
|
"keepParameterSorting": {
|
|
580
525
|
"char": "k",
|
|
581
526
|
"description": "Prevents alphabetical sorting of the URL parameters",
|
|
582
527
|
"name": "keepParameterSorting",
|
|
583
528
|
"allowNo": false,
|
|
584
529
|
"type": "boolean"
|
|
530
|
+
},
|
|
531
|
+
"quiet": {
|
|
532
|
+
"char": "q",
|
|
533
|
+
"description": "less output non interactive",
|
|
534
|
+
"name": "quiet",
|
|
535
|
+
"allowNo": false,
|
|
536
|
+
"type": "boolean"
|
|
537
|
+
},
|
|
538
|
+
"delay": {
|
|
539
|
+
"char": "d",
|
|
540
|
+
"deprecated": true,
|
|
541
|
+
"description": "Request delay in ms (deprecated)",
|
|
542
|
+
"name": "delay",
|
|
543
|
+
"hasDynamicHelp": false,
|
|
544
|
+
"multiple": false,
|
|
545
|
+
"type": "option"
|
|
585
546
|
}
|
|
586
547
|
},
|
|
587
548
|
"hasDynamicHelp": false,
|
|
@@ -699,5 +660,5 @@
|
|
|
699
660
|
]
|
|
700
661
|
}
|
|
701
662
|
},
|
|
702
|
-
"version": "2.
|
|
663
|
+
"version": "2.23.0"
|
|
703
664
|
}
|
package/package.json
CHANGED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { Command } from "@oclif/core";
|
|
2
|
-
import { EntityManager } from "baqend";
|
|
3
|
-
export default class PopPrewarm extends Command {
|
|
4
|
-
static description: string;
|
|
5
|
-
static args: {
|
|
6
|
-
app: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
-
};
|
|
8
|
-
static flags: {
|
|
9
|
-
ips: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
10
|
-
contentTypes: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
11
|
-
};
|
|
12
|
-
static examples: string[];
|
|
13
|
-
run(): Promise<void>;
|
|
14
|
-
getCount(database: EntityManager, contentTypes: string[]): Promise<any>;
|
|
15
|
-
queryDb(database: EntityManager, contentTypes: string[], lastId?: string): Promise<any>;
|
|
16
|
-
fetchAssets(database: EntityManager, ips: string[], contentTypes: string[], app: string, progress: any, lastId?: string): Promise<any>;
|
|
17
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const tslib_1 = require("tslib");
|
|
4
|
-
const core_1 = require("@oclif/core");
|
|
5
|
-
const cli_1 = require("baqend/cli");
|
|
6
|
-
const core_2 = require("@oclif/core");
|
|
7
|
-
const prewarm_service_1 = tslib_1.__importDefault(require("../services/prewarm-service"));
|
|
8
|
-
const cli_parameters_1 = require("../models/cli-parameters");
|
|
9
|
-
const logging_helper_1 = require("../helpers/logging-helper");
|
|
10
|
-
class PopPrewarm extends core_1.Command {
|
|
11
|
-
static description = "Pre-warm Fastly PoPs";
|
|
12
|
-
static args = {
|
|
13
|
-
[cli_parameters_1.CLIParameters.AppName]: core_1.Args.string({
|
|
14
|
-
name: cli_parameters_1.CLIParameters.AppName, // name of arg to show in help and reference with args[name]
|
|
15
|
-
required: true, // make the arg required with `required: true`
|
|
16
|
-
description: "The customers appName", // help description
|
|
17
|
-
hidden: false, // hide this arg from help
|
|
18
|
-
}),
|
|
19
|
-
};
|
|
20
|
-
static flags = {
|
|
21
|
-
[cli_parameters_1.CLIParameters.Ips]: core_1.Flags.string({
|
|
22
|
-
default: "151.101.120.194",
|
|
23
|
-
char: cli_parameters_1.CLIParametersChar.Ips,
|
|
24
|
-
}),
|
|
25
|
-
[cli_parameters_1.CLIParameters.ContentTypes]: core_1.Flags.string({
|
|
26
|
-
default: "image",
|
|
27
|
-
char: cli_parameters_1.CLIParametersChar.ContentTypes,
|
|
28
|
-
}),
|
|
29
|
-
};
|
|
30
|
-
static examples = [
|
|
31
|
-
`$ sk pop-prewarm <${cli_parameters_1.CLIParameters.AppName}> -${cli_parameters_1.CLIParametersChar.ContentTypes} <${cli_parameters_1.CLIParameters.ContentTypes}> -${cli_parameters_1.CLIParametersChar.Ips} <${cli_parameters_1.CLIParameters.Ips}>`,
|
|
32
|
-
`$ sk pop-prewarm decathlon -${cli_parameters_1.CLIParametersChar.ContentTypes} ${cli_parameters_1.CLIParametersExample.ContentTypes} -${cli_parameters_1.CLIParametersChar.Ips} ${cli_parameters_1.CLIParametersExample.Ips}`,
|
|
33
|
-
];
|
|
34
|
-
async run() {
|
|
35
|
-
const { args: { app }, flags: { ips, contentTypes }, } = await this.parse(PopPrewarm);
|
|
36
|
-
const database = await cli_1.account.login({ app });
|
|
37
|
-
const contentTypeArray = contentTypes.split(",");
|
|
38
|
-
const ipsArray = ips.split(",");
|
|
39
|
-
const count = await this.getCount(database, contentTypeArray);
|
|
40
|
-
const progress = core_2.ux.progress();
|
|
41
|
-
progress.start(count * ips.length, 0);
|
|
42
|
-
await this.fetchAssets(database, ipsArray, contentTypeArray, app, progress);
|
|
43
|
-
progress.stop();
|
|
44
|
-
}
|
|
45
|
-
async getCount(database, contentTypes) {
|
|
46
|
-
return database["speedKit.Asset"]
|
|
47
|
-
.find()
|
|
48
|
-
.in("contentType", contentTypes)
|
|
49
|
-
.count();
|
|
50
|
-
}
|
|
51
|
-
async queryDb(database, contentTypes, lastId = "") {
|
|
52
|
-
let qb = database["speedKit.Asset"].find().in("contentType", contentTypes);
|
|
53
|
-
if (lastId) {
|
|
54
|
-
qb = qb.gt("id", lastId);
|
|
55
|
-
}
|
|
56
|
-
return qb.limit(100).sort({ id: 1 }).resultList();
|
|
57
|
-
}
|
|
58
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
59
|
-
async fetchAssets(database, ips, contentTypes, app, progress, lastId = "") {
|
|
60
|
-
const resultList = await this.queryDb(database, contentTypes, lastId);
|
|
61
|
-
if (resultList.length === 0) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
const assetChunks = prewarm_service_1.default.chunk(resultList, 50);
|
|
65
|
-
let fetches = [];
|
|
66
|
-
for (const assets of assetChunks) {
|
|
67
|
-
for (const ip of ips) {
|
|
68
|
-
for (const asset of assets) {
|
|
69
|
-
let { url } = asset;
|
|
70
|
-
const { origin, variation, extendedURL } = asset;
|
|
71
|
-
url += extendedURL || "";
|
|
72
|
-
fetches.push(prewarm_service_1.default.fetchURLByIp(ip, url, origin, variation, app, database.token));
|
|
73
|
-
}
|
|
74
|
-
try {
|
|
75
|
-
// eslint-disable-next-line no-await-in-loop
|
|
76
|
-
await Promise.all(fetches);
|
|
77
|
-
}
|
|
78
|
-
catch (error) {
|
|
79
|
-
(0, logging_helper_1.logWarning)(error);
|
|
80
|
-
}
|
|
81
|
-
progress.increment(fetches.length);
|
|
82
|
-
fetches = [];
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
database.clear();
|
|
86
|
-
this.log(resultList.at(-1).url);
|
|
87
|
-
return this.fetchAssets(database, ips, contentTypes, app, progress, resultList.at(-1).id);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
exports.default = PopPrewarm;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { CliService } from "./cli-service";
|
|
2
|
-
export default abstract class Hooks {
|
|
3
|
-
readonly preHook?: string;
|
|
4
|
-
readonly postHook?: string;
|
|
5
|
-
protected cli: CliService;
|
|
6
|
-
protected constructor(cli: CliService, preHook?: string, postHook?: string);
|
|
7
|
-
run(): Promise<any>;
|
|
8
|
-
runPreHook(): Promise<void>;
|
|
9
|
-
runPostHook(): Promise<void>;
|
|
10
|
-
abstract _run(): Promise<any>;
|
|
11
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const node_child_process_1 = require("node:child_process");
|
|
4
|
-
class Hooks {
|
|
5
|
-
preHook;
|
|
6
|
-
postHook;
|
|
7
|
-
cli;
|
|
8
|
-
constructor(cli, preHook, postHook) {
|
|
9
|
-
this.cli = cli;
|
|
10
|
-
this.preHook = preHook;
|
|
11
|
-
this.postHook = postHook;
|
|
12
|
-
}
|
|
13
|
-
async run() {
|
|
14
|
-
await this.runPreHook();
|
|
15
|
-
await this._run();
|
|
16
|
-
await this.runPostHook();
|
|
17
|
-
}
|
|
18
|
-
async runPreHook() {
|
|
19
|
-
if (!this.preHook) {
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
this.cli.writeSuccess(this.preHook);
|
|
23
|
-
this.cli.write((0, node_child_process_1.execSync)(this.preHook) + "");
|
|
24
|
-
}
|
|
25
|
-
async runPostHook() {
|
|
26
|
-
if (!this.postHook) {
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
this.cli.writeSuccess(this.postHook);
|
|
30
|
-
this.cli.write((0, node_child_process_1.execSync)(this.postHook) + "");
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
exports.default = Hooks;
|