@chirpier/chirpier-js 0.3.0 → 0.4.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/README.md +5 -0
- package/dist/__tests__/chirpier.test.js +304 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +100 -10
- package/package.json +1 -1
- package/src/__tests__/chirpier.test.ts +200 -1
- package/src/index.ts +113 -11
package/README.md
CHANGED
|
@@ -76,6 +76,11 @@ Default servicer endpoint is `https://api.chirpier.co/v1.0`.
|
|
|
76
76
|
The same bearer token is used for both ingest and servicer APIs.
|
|
77
77
|
Queued logs are not dropped locally because of queue capacity or retry exhaustion.
|
|
78
78
|
|
|
79
|
+
### Retry behavior
|
|
80
|
+
|
|
81
|
+
The SDK retries network/transport failures, `429` responses, and retryable `5xx` responses such as `502` and `504`.
|
|
82
|
+
It does not retry `401`, `403`, `404`, `500`, or `503`, and `401`/`403` errors surface the Chirpier response message when available.
|
|
83
|
+
|
|
79
84
|
### `logEvent(log)`
|
|
80
85
|
|
|
81
86
|
Queues a log for batched delivery.
|
|
@@ -50,7 +50,10 @@ describe("Chirpier SDK", function () {
|
|
|
50
50
|
afterEach(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
51
51
|
return __generator(this, function (_a) {
|
|
52
52
|
switch (_a.label) {
|
|
53
|
-
case 0:
|
|
53
|
+
case 0:
|
|
54
|
+
jest.useRealTimers();
|
|
55
|
+
jest.restoreAllMocks();
|
|
56
|
+
return [4 /*yield*/, (0, index_1.stop)()];
|
|
54
57
|
case 1:
|
|
55
58
|
_a.sent();
|
|
56
59
|
return [2 /*return*/];
|
|
@@ -450,6 +453,306 @@ describe("Chirpier SDK", function () {
|
|
|
450
453
|
}
|
|
451
454
|
});
|
|
452
455
|
}); });
|
|
456
|
+
test("retries network errors", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
457
|
+
var client, axiosBackedClient, attempts, flushPromise;
|
|
458
|
+
return __generator(this, function (_a) {
|
|
459
|
+
switch (_a.label) {
|
|
460
|
+
case 0:
|
|
461
|
+
jest.useFakeTimers();
|
|
462
|
+
client = (0, index_1.createClient)({
|
|
463
|
+
key: "chp_network_retry_key",
|
|
464
|
+
retries: 2,
|
|
465
|
+
flushDelay: 10000,
|
|
466
|
+
});
|
|
467
|
+
axiosBackedClient = client;
|
|
468
|
+
attempts = 0;
|
|
469
|
+
axiosBackedClient.axiosInstance.defaults.adapter = function (config) { return __awaiter(void 0, void 0, void 0, function () {
|
|
470
|
+
return __generator(this, function (_a) {
|
|
471
|
+
attempts += 1;
|
|
472
|
+
if (attempts < 3) {
|
|
473
|
+
throw Object.assign(new Error("Network Error"), {
|
|
474
|
+
code: "ECONNRESET",
|
|
475
|
+
config: config,
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
return [2 /*return*/, {
|
|
479
|
+
data: { success: true },
|
|
480
|
+
status: 200,
|
|
481
|
+
statusText: "OK",
|
|
482
|
+
headers: {},
|
|
483
|
+
config: config,
|
|
484
|
+
}];
|
|
485
|
+
});
|
|
486
|
+
}); };
|
|
487
|
+
_a.label = 1;
|
|
488
|
+
case 1:
|
|
489
|
+
_a.trys.push([1, , 5, 7]);
|
|
490
|
+
return [4 /*yield*/, client.log({ event: "network.retry", value: 1 })];
|
|
491
|
+
case 2:
|
|
492
|
+
_a.sent();
|
|
493
|
+
flushPromise = client.flush();
|
|
494
|
+
return [4 /*yield*/, jest.runAllTimersAsync()];
|
|
495
|
+
case 3:
|
|
496
|
+
_a.sent();
|
|
497
|
+
return [4 /*yield*/, expect(flushPromise).resolves.toBeUndefined()];
|
|
498
|
+
case 4:
|
|
499
|
+
_a.sent();
|
|
500
|
+
expect(attempts).toBe(3);
|
|
501
|
+
return [3 /*break*/, 7];
|
|
502
|
+
case 5: return [4 /*yield*/, client.shutdown()];
|
|
503
|
+
case 6:
|
|
504
|
+
_a.sent();
|
|
505
|
+
return [7 /*endfinally*/];
|
|
506
|
+
case 7: return [2 /*return*/];
|
|
507
|
+
}
|
|
508
|
+
});
|
|
509
|
+
}); });
|
|
510
|
+
test("retries 429 responses", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
511
|
+
var mock, client, flushPromise;
|
|
512
|
+
return __generator(this, function (_a) {
|
|
513
|
+
switch (_a.label) {
|
|
514
|
+
case 0:
|
|
515
|
+
jest.useFakeTimers();
|
|
516
|
+
mock = new axios_mock_adapter_1.default(axios_1.default);
|
|
517
|
+
mock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(429, { error: "rate limited" }, { "retry-after": "1" });
|
|
518
|
+
mock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(429, { error: "rate limited" }, { "retry-after": "1" });
|
|
519
|
+
mock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(200, { success: true });
|
|
520
|
+
client = (0, index_1.createClient)({
|
|
521
|
+
key: "chp_rate_limit_key",
|
|
522
|
+
retries: 2,
|
|
523
|
+
flushDelay: 10000,
|
|
524
|
+
});
|
|
525
|
+
_a.label = 1;
|
|
526
|
+
case 1:
|
|
527
|
+
_a.trys.push([1, , 5, 7]);
|
|
528
|
+
return [4 /*yield*/, client.log({ event: "rate.limit", value: 1 })];
|
|
529
|
+
case 2:
|
|
530
|
+
_a.sent();
|
|
531
|
+
flushPromise = client.flush();
|
|
532
|
+
return [4 /*yield*/, jest.runAllTimersAsync()];
|
|
533
|
+
case 3:
|
|
534
|
+
_a.sent();
|
|
535
|
+
return [4 /*yield*/, expect(flushPromise).resolves.toBeUndefined()];
|
|
536
|
+
case 4:
|
|
537
|
+
_a.sent();
|
|
538
|
+
expect(mock.history.post.length).toBe(3);
|
|
539
|
+
return [3 /*break*/, 7];
|
|
540
|
+
case 5: return [4 /*yield*/, client.shutdown()];
|
|
541
|
+
case 6:
|
|
542
|
+
_a.sent();
|
|
543
|
+
return [7 /*endfinally*/];
|
|
544
|
+
case 7: return [2 /*return*/];
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
}); });
|
|
548
|
+
test("does not retry 401 and logs the Chirpier response message", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
549
|
+
var mock, errorSpy, client;
|
|
550
|
+
return __generator(this, function (_a) {
|
|
551
|
+
switch (_a.label) {
|
|
552
|
+
case 0:
|
|
553
|
+
mock = new axios_mock_adapter_1.default(axios_1.default);
|
|
554
|
+
errorSpy = jest.spyOn(console, "error").mockImplementation(function () { return undefined; });
|
|
555
|
+
mock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(401, { error: "invalid api key" });
|
|
556
|
+
client = (0, index_1.createClient)({
|
|
557
|
+
key: "chp_unauthorized_key",
|
|
558
|
+
retries: 3,
|
|
559
|
+
flushDelay: 10000,
|
|
560
|
+
logLevel: 1 /* LogLevel.Error */,
|
|
561
|
+
});
|
|
562
|
+
_a.label = 1;
|
|
563
|
+
case 1:
|
|
564
|
+
_a.trys.push([1, , 5, 7]);
|
|
565
|
+
return [4 /*yield*/, client.log({ event: "auth.failed", value: 1 })];
|
|
566
|
+
case 2:
|
|
567
|
+
_a.sent();
|
|
568
|
+
return [4 /*yield*/, client.flush()];
|
|
569
|
+
case 3:
|
|
570
|
+
_a.sent();
|
|
571
|
+
return [4 /*yield*/, client.flush()];
|
|
572
|
+
case 4:
|
|
573
|
+
_a.sent();
|
|
574
|
+
expect(mock.history.post.length).toBe(1);
|
|
575
|
+
expect(errorSpy).toHaveBeenCalledWith("Chirpier API returned 401: invalid api key");
|
|
576
|
+
return [3 /*break*/, 7];
|
|
577
|
+
case 5: return [4 /*yield*/, client.shutdown()];
|
|
578
|
+
case 6:
|
|
579
|
+
_a.sent();
|
|
580
|
+
return [7 /*endfinally*/];
|
|
581
|
+
case 7: return [2 /*return*/];
|
|
582
|
+
}
|
|
583
|
+
});
|
|
584
|
+
}); });
|
|
585
|
+
test("does not retry 403 and logs the Chirpier response message", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
586
|
+
var mock, errorSpy, client;
|
|
587
|
+
return __generator(this, function (_a) {
|
|
588
|
+
switch (_a.label) {
|
|
589
|
+
case 0:
|
|
590
|
+
mock = new axios_mock_adapter_1.default(axios_1.default);
|
|
591
|
+
errorSpy = jest.spyOn(console, "error").mockImplementation(function () { return undefined; });
|
|
592
|
+
mock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(403, { message: "project is disabled" });
|
|
593
|
+
client = (0, index_1.createClient)({
|
|
594
|
+
key: "chp_forbidden_key",
|
|
595
|
+
retries: 3,
|
|
596
|
+
flushDelay: 10000,
|
|
597
|
+
logLevel: 1 /* LogLevel.Error */,
|
|
598
|
+
});
|
|
599
|
+
_a.label = 1;
|
|
600
|
+
case 1:
|
|
601
|
+
_a.trys.push([1, , 5, 7]);
|
|
602
|
+
return [4 /*yield*/, client.log({ event: "auth.forbidden", value: 1 })];
|
|
603
|
+
case 2:
|
|
604
|
+
_a.sent();
|
|
605
|
+
return [4 /*yield*/, client.flush()];
|
|
606
|
+
case 3:
|
|
607
|
+
_a.sent();
|
|
608
|
+
return [4 /*yield*/, client.flush()];
|
|
609
|
+
case 4:
|
|
610
|
+
_a.sent();
|
|
611
|
+
expect(mock.history.post.length).toBe(1);
|
|
612
|
+
expect(errorSpy).toHaveBeenCalledWith("Chirpier API returned 403: project is disabled");
|
|
613
|
+
return [3 /*break*/, 7];
|
|
614
|
+
case 5: return [4 /*yield*/, client.shutdown()];
|
|
615
|
+
case 6:
|
|
616
|
+
_a.sent();
|
|
617
|
+
return [7 /*endfinally*/];
|
|
618
|
+
case 7: return [2 /*return*/];
|
|
619
|
+
}
|
|
620
|
+
});
|
|
621
|
+
}); });
|
|
622
|
+
test.each([404, 500, 503])("does not retry non-retryable status %s", function (status) { return __awaiter(void 0, void 0, void 0, function () {
|
|
623
|
+
var mock, client;
|
|
624
|
+
return __generator(this, function (_a) {
|
|
625
|
+
switch (_a.label) {
|
|
626
|
+
case 0:
|
|
627
|
+
mock = new axios_mock_adapter_1.default(axios_1.default);
|
|
628
|
+
mock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(status, { error: "http ".concat(status) });
|
|
629
|
+
client = (0, index_1.createClient)({
|
|
630
|
+
key: "chp_non_retryable_".concat(status),
|
|
631
|
+
retries: 3,
|
|
632
|
+
flushDelay: 10000,
|
|
633
|
+
});
|
|
634
|
+
_a.label = 1;
|
|
635
|
+
case 1:
|
|
636
|
+
_a.trys.push([1, , 5, 7]);
|
|
637
|
+
return [4 /*yield*/, client.log({ event: "non.retryable.".concat(status), value: 1 })];
|
|
638
|
+
case 2:
|
|
639
|
+
_a.sent();
|
|
640
|
+
return [4 /*yield*/, client.flush()];
|
|
641
|
+
case 3:
|
|
642
|
+
_a.sent();
|
|
643
|
+
return [4 /*yield*/, client.flush()];
|
|
644
|
+
case 4:
|
|
645
|
+
_a.sent();
|
|
646
|
+
expect(mock.history.post.length).toBe(1);
|
|
647
|
+
return [3 /*break*/, 7];
|
|
648
|
+
case 5: return [4 /*yield*/, client.shutdown()];
|
|
649
|
+
case 6:
|
|
650
|
+
_a.sent();
|
|
651
|
+
return [7 /*endfinally*/];
|
|
652
|
+
case 7: return [2 /*return*/];
|
|
653
|
+
}
|
|
654
|
+
});
|
|
655
|
+
}); });
|
|
656
|
+
test("retries 502 responses", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
657
|
+
var mock, client, flushPromise;
|
|
658
|
+
return __generator(this, function (_a) {
|
|
659
|
+
switch (_a.label) {
|
|
660
|
+
case 0:
|
|
661
|
+
jest.useFakeTimers();
|
|
662
|
+
mock = new axios_mock_adapter_1.default(axios_1.default);
|
|
663
|
+
mock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(502, { error: "bad gateway" });
|
|
664
|
+
mock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(502, { error: "bad gateway" });
|
|
665
|
+
mock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(200, { success: true });
|
|
666
|
+
client = (0, index_1.createClient)({
|
|
667
|
+
key: "chp_bad_gateway_key",
|
|
668
|
+
retries: 2,
|
|
669
|
+
flushDelay: 10000,
|
|
670
|
+
});
|
|
671
|
+
_a.label = 1;
|
|
672
|
+
case 1:
|
|
673
|
+
_a.trys.push([1, , 5, 7]);
|
|
674
|
+
return [4 /*yield*/, client.log({ event: "bad.gateway", value: 1 })];
|
|
675
|
+
case 2:
|
|
676
|
+
_a.sent();
|
|
677
|
+
flushPromise = client.flush();
|
|
678
|
+
return [4 /*yield*/, jest.runAllTimersAsync()];
|
|
679
|
+
case 3:
|
|
680
|
+
_a.sent();
|
|
681
|
+
return [4 /*yield*/, expect(flushPromise).resolves.toBeUndefined()];
|
|
682
|
+
case 4:
|
|
683
|
+
_a.sent();
|
|
684
|
+
expect(mock.history.post.length).toBe(3);
|
|
685
|
+
return [3 /*break*/, 7];
|
|
686
|
+
case 5: return [4 /*yield*/, client.shutdown()];
|
|
687
|
+
case 6:
|
|
688
|
+
_a.sent();
|
|
689
|
+
return [7 /*endfinally*/];
|
|
690
|
+
case 7: return [2 /*return*/];
|
|
691
|
+
}
|
|
692
|
+
});
|
|
693
|
+
}); });
|
|
694
|
+
test("flush requeues only retryable failures", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
695
|
+
var retryableMock, retryableClient, nonRetryableMock, nonRetryableClient;
|
|
696
|
+
return __generator(this, function (_a) {
|
|
697
|
+
switch (_a.label) {
|
|
698
|
+
case 0:
|
|
699
|
+
retryableMock = new axios_mock_adapter_1.default(axios_1.default);
|
|
700
|
+
retryableMock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(502, { error: "bad gateway" });
|
|
701
|
+
retryableMock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(200, { success: true });
|
|
702
|
+
retryableClient = (0, index_1.createClient)({
|
|
703
|
+
key: "chp_retryable_requeue_key",
|
|
704
|
+
retries: 0,
|
|
705
|
+
flushDelay: 10000,
|
|
706
|
+
});
|
|
707
|
+
_a.label = 1;
|
|
708
|
+
case 1:
|
|
709
|
+
_a.trys.push([1, , 5, 7]);
|
|
710
|
+
return [4 /*yield*/, retryableClient.log({ event: "retryable.requeue", value: 1 })];
|
|
711
|
+
case 2:
|
|
712
|
+
_a.sent();
|
|
713
|
+
return [4 /*yield*/, retryableClient.flush()];
|
|
714
|
+
case 3:
|
|
715
|
+
_a.sent();
|
|
716
|
+
return [4 /*yield*/, retryableClient.flush()];
|
|
717
|
+
case 4:
|
|
718
|
+
_a.sent();
|
|
719
|
+
expect(retryableMock.history.post.length).toBe(2);
|
|
720
|
+
return [3 /*break*/, 7];
|
|
721
|
+
case 5: return [4 /*yield*/, retryableClient.shutdown()];
|
|
722
|
+
case 6:
|
|
723
|
+
_a.sent();
|
|
724
|
+
return [7 /*endfinally*/];
|
|
725
|
+
case 7:
|
|
726
|
+
nonRetryableMock = new axios_mock_adapter_1.default(axios_1.default);
|
|
727
|
+
nonRetryableMock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(404, { error: "not found" });
|
|
728
|
+
nonRetryableClient = (0, index_1.createClient)({
|
|
729
|
+
key: "chp_non_retryable_requeue_key",
|
|
730
|
+
retries: 0,
|
|
731
|
+
flushDelay: 10000,
|
|
732
|
+
logLevel: 0 /* LogLevel.None */,
|
|
733
|
+
});
|
|
734
|
+
_a.label = 8;
|
|
735
|
+
case 8:
|
|
736
|
+
_a.trys.push([8, , 12, 14]);
|
|
737
|
+
return [4 /*yield*/, nonRetryableClient.log({ event: "non.retryable.drop", value: 1 })];
|
|
738
|
+
case 9:
|
|
739
|
+
_a.sent();
|
|
740
|
+
return [4 /*yield*/, nonRetryableClient.flush()];
|
|
741
|
+
case 10:
|
|
742
|
+
_a.sent();
|
|
743
|
+
return [4 /*yield*/, nonRetryableClient.flush()];
|
|
744
|
+
case 11:
|
|
745
|
+
_a.sent();
|
|
746
|
+
expect(nonRetryableMock.history.post.length).toBe(1);
|
|
747
|
+
return [3 /*break*/, 14];
|
|
748
|
+
case 12: return [4 /*yield*/, nonRetryableClient.shutdown()];
|
|
749
|
+
case 13:
|
|
750
|
+
_a.sent();
|
|
751
|
+
return [7 /*endfinally*/];
|
|
752
|
+
case 14: return [2 /*return*/];
|
|
753
|
+
}
|
|
754
|
+
});
|
|
755
|
+
}); });
|
|
453
756
|
test("getEventLogs uses servicer endpoint with period, limit, and offset", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
454
757
|
var mock, client;
|
|
455
758
|
return __generator(this, function (_a) {
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -99,6 +99,83 @@ var ChirpierError = /** @class */ (function (_super) {
|
|
|
99
99
|
return ChirpierError;
|
|
100
100
|
}(Error));
|
|
101
101
|
exports.ChirpierError = ChirpierError;
|
|
102
|
+
function classifyLogResponseStatus(status) {
|
|
103
|
+
if (status === undefined) {
|
|
104
|
+
return "success";
|
|
105
|
+
}
|
|
106
|
+
if (status === 429) {
|
|
107
|
+
return "retry_after";
|
|
108
|
+
}
|
|
109
|
+
if (status >= 500) {
|
|
110
|
+
if (status === 500 || status === 503) {
|
|
111
|
+
return "non_retryable";
|
|
112
|
+
}
|
|
113
|
+
return "retryable";
|
|
114
|
+
}
|
|
115
|
+
if (status >= 400) {
|
|
116
|
+
return "non_retryable";
|
|
117
|
+
}
|
|
118
|
+
return "success";
|
|
119
|
+
}
|
|
120
|
+
function getChirpierResponseMessage(data) {
|
|
121
|
+
if (typeof data === "string") {
|
|
122
|
+
var trimmed = data.trim();
|
|
123
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
124
|
+
}
|
|
125
|
+
if (data && typeof data === "object") {
|
|
126
|
+
var record = data;
|
|
127
|
+
if (typeof record.message === "string" && record.message.trim().length > 0) {
|
|
128
|
+
return record.message.trim();
|
|
129
|
+
}
|
|
130
|
+
if (typeof record.error === "string" && record.error.trim().length > 0) {
|
|
131
|
+
return record.error.trim();
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
return JSON.stringify(data);
|
|
135
|
+
}
|
|
136
|
+
catch (_a) {
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
function getRetryDelayMs(retryCount, error) {
|
|
143
|
+
var _a, _b;
|
|
144
|
+
if (axios_1.default.isAxiosError(error) && ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 429) {
|
|
145
|
+
var retryAfterHeader = (_b = error.response.headers) === null || _b === void 0 ? void 0 : _b["retry-after"];
|
|
146
|
+
var retryAfterSeconds = Number(retryAfterHeader);
|
|
147
|
+
if (Number.isFinite(retryAfterSeconds) && retryAfterSeconds >= 0) {
|
|
148
|
+
return retryAfterSeconds * 1000;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
var baseDelay = Math.pow(2, retryCount) * 1000;
|
|
152
|
+
var jitter = Math.random() * 0.3 * baseDelay;
|
|
153
|
+
return baseDelay + jitter;
|
|
154
|
+
}
|
|
155
|
+
function normalizeSendLogsError(error, logLevel) {
|
|
156
|
+
var _a, _b;
|
|
157
|
+
if (!axios_1.default.isAxiosError(error)) {
|
|
158
|
+
return error;
|
|
159
|
+
}
|
|
160
|
+
var status = (_a = error.response) === null || _a === void 0 ? void 0 : _a.status;
|
|
161
|
+
if (classifyLogResponseStatus(status) !== "non_retryable") {
|
|
162
|
+
return error;
|
|
163
|
+
}
|
|
164
|
+
var responseMessage = getChirpierResponseMessage((_b = error.response) === null || _b === void 0 ? void 0 : _b.data);
|
|
165
|
+
if ((status === 401 || status === 403) && logLevel >= 1 /* LogLevel.Error */) {
|
|
166
|
+
if (responseMessage) {
|
|
167
|
+
console.error("Chirpier API returned ".concat(status, ": ").concat(responseMessage));
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
console.error("Chirpier API returned ".concat(status));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
var message = responseMessage ? "HTTP ".concat(status, ": ").concat(responseMessage) : "HTTP ".concat(status);
|
|
174
|
+
return new ChirpierError(message, "NON_RETRYABLE_RESPONSE");
|
|
175
|
+
}
|
|
176
|
+
function isNonRetryableLogError(error) {
|
|
177
|
+
return error instanceof ChirpierError && error.code === "NON_RETRYABLE_RESPONSE";
|
|
178
|
+
}
|
|
102
179
|
var Client = /** @class */ (function () {
|
|
103
180
|
function Client(options) {
|
|
104
181
|
if (options === void 0) { options = {}; }
|
|
@@ -158,15 +235,15 @@ var Client = /** @class */ (function () {
|
|
|
158
235
|
this.axiosInstance.interceptors.response.use(function (response) { return response; }, function (error) { return Promise.reject(error); });
|
|
159
236
|
(0, axios_retry_1.default)(this.axiosInstance, {
|
|
160
237
|
retries: this.retries,
|
|
161
|
-
retryDelay: function (retryCount) {
|
|
162
|
-
var baseDelay = Math.pow(2, retryCount) * 1000;
|
|
163
|
-
var jitter = Math.random() * 0.3 * baseDelay;
|
|
164
|
-
return baseDelay + jitter;
|
|
165
|
-
},
|
|
238
|
+
retryDelay: function (retryCount, error) { return getRetryDelayMs(retryCount, error); },
|
|
166
239
|
retryCondition: function (error) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
240
|
+
var _a;
|
|
241
|
+
if (axios_retry_1.default.isNetworkError(error)) {
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
var status = (_a = error.response) === null || _a === void 0 ? void 0 : _a.status;
|
|
245
|
+
var retryPolicy = classifyLogResponseStatus(status);
|
|
246
|
+
return retryPolicy === "retryable" || retryPolicy === "retry_after";
|
|
170
247
|
},
|
|
171
248
|
shouldResetTimeout: true,
|
|
172
249
|
});
|
|
@@ -317,6 +394,12 @@ var Client = /** @class */ (function () {
|
|
|
317
394
|
if (this.logLevel >= 1 /* LogLevel.Error */) {
|
|
318
395
|
console.error("Failed to send logs:", error_1);
|
|
319
396
|
}
|
|
397
|
+
if (isNonRetryableLogError(error_1)) {
|
|
398
|
+
if (this.logLevel >= 1 /* LogLevel.Error */) {
|
|
399
|
+
console.error("Dropping logs after non-retryable response from API");
|
|
400
|
+
}
|
|
401
|
+
return [2 /*return*/];
|
|
402
|
+
}
|
|
320
403
|
return [4 /*yield*/, this.queueLock.acquire("logQueue", function () { return __awaiter(_this, void 0, void 0, function () {
|
|
321
404
|
return __generator(this, function (_a) {
|
|
322
405
|
this.logQueue = __spreadArray(__spreadArray([], logsToSend, true), this.logQueue, true);
|
|
@@ -339,12 +422,19 @@ var Client = /** @class */ (function () {
|
|
|
339
422
|
};
|
|
340
423
|
Client.prototype.sendLogs = function (logs) {
|
|
341
424
|
return __awaiter(this, void 0, void 0, function () {
|
|
425
|
+
var error_2;
|
|
342
426
|
return __generator(this, function (_a) {
|
|
343
427
|
switch (_a.label) {
|
|
344
|
-
case 0:
|
|
428
|
+
case 0:
|
|
429
|
+
_a.trys.push([0, 2, , 3]);
|
|
430
|
+
return [4 /*yield*/, this.axiosInstance.post(this.apiEndpoint, logs)];
|
|
345
431
|
case 1:
|
|
346
432
|
_a.sent();
|
|
347
|
-
return [
|
|
433
|
+
return [3 /*break*/, 3];
|
|
434
|
+
case 2:
|
|
435
|
+
error_2 = _a.sent();
|
|
436
|
+
throw normalizeSendLogsError(error_2, this.logLevel);
|
|
437
|
+
case 3: return [2 /*return*/];
|
|
348
438
|
}
|
|
349
439
|
});
|
|
350
440
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import os from "os";
|
|
3
3
|
import path from "path";
|
|
4
|
-
import axios from "axios";
|
|
4
|
+
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
|
|
5
5
|
import MockAdapter from "axios-mock-adapter";
|
|
6
6
|
import {
|
|
7
7
|
Client,
|
|
@@ -20,6 +20,8 @@ import {
|
|
|
20
20
|
|
|
21
21
|
describe("Chirpier SDK", () => {
|
|
22
22
|
afterEach(async () => {
|
|
23
|
+
jest.useRealTimers();
|
|
24
|
+
jest.restoreAllMocks();
|
|
23
25
|
await stop();
|
|
24
26
|
});
|
|
25
27
|
|
|
@@ -341,6 +343,203 @@ describe("Chirpier SDK", () => {
|
|
|
341
343
|
expect(JSON.parse(mock.history.post[0].data)[0].event).toBe("queued.before.flush");
|
|
342
344
|
});
|
|
343
345
|
|
|
346
|
+
test("retries network errors", async () => {
|
|
347
|
+
jest.useFakeTimers();
|
|
348
|
+
const client: Client = createClient({
|
|
349
|
+
key: "chp_network_retry_key",
|
|
350
|
+
retries: 2,
|
|
351
|
+
flushDelay: 10000,
|
|
352
|
+
});
|
|
353
|
+
const axiosBackedClient = client as unknown as { axiosInstance: AxiosInstance };
|
|
354
|
+
let attempts = 0;
|
|
355
|
+
axiosBackedClient.axiosInstance.defaults.adapter = async (
|
|
356
|
+
config: AxiosRequestConfig
|
|
357
|
+
): Promise<AxiosResponse> => {
|
|
358
|
+
attempts += 1;
|
|
359
|
+
if (attempts < 3) {
|
|
360
|
+
throw Object.assign(new Error("Network Error"), {
|
|
361
|
+
code: "ECONNRESET",
|
|
362
|
+
config,
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return {
|
|
367
|
+
data: { success: true },
|
|
368
|
+
status: 200,
|
|
369
|
+
statusText: "OK",
|
|
370
|
+
headers: {},
|
|
371
|
+
config,
|
|
372
|
+
};
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
try {
|
|
376
|
+
await client.log({ event: "network.retry", value: 1 });
|
|
377
|
+
const flushPromise = client.flush();
|
|
378
|
+
await jest.runAllTimersAsync();
|
|
379
|
+
await expect(flushPromise).resolves.toBeUndefined();
|
|
380
|
+
expect(attempts).toBe(3);
|
|
381
|
+
} finally {
|
|
382
|
+
await client.shutdown();
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
test("retries 429 responses", async () => {
|
|
387
|
+
jest.useFakeTimers();
|
|
388
|
+
const mock = new MockAdapter(axios);
|
|
389
|
+
mock.onPost(DEFAULT_API_ENDPOINT).replyOnce(429, { error: "rate limited" }, { "retry-after": "1" });
|
|
390
|
+
mock.onPost(DEFAULT_API_ENDPOINT).replyOnce(429, { error: "rate limited" }, { "retry-after": "1" });
|
|
391
|
+
mock.onPost(DEFAULT_API_ENDPOINT).replyOnce(200, { success: true });
|
|
392
|
+
|
|
393
|
+
const client: Client = createClient({
|
|
394
|
+
key: "chp_rate_limit_key",
|
|
395
|
+
retries: 2,
|
|
396
|
+
flushDelay: 10000,
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
try {
|
|
400
|
+
await client.log({ event: "rate.limit", value: 1 });
|
|
401
|
+
const flushPromise = client.flush();
|
|
402
|
+
await jest.runAllTimersAsync();
|
|
403
|
+
await expect(flushPromise).resolves.toBeUndefined();
|
|
404
|
+
expect(mock.history.post.length).toBe(3);
|
|
405
|
+
} finally {
|
|
406
|
+
await client.shutdown();
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
test("does not retry 401 and logs the Chirpier response message", async () => {
|
|
411
|
+
const mock = new MockAdapter(axios);
|
|
412
|
+
const errorSpy = jest.spyOn(console, "error").mockImplementation(() => undefined);
|
|
413
|
+
mock.onPost(DEFAULT_API_ENDPOINT).replyOnce(401, { error: "invalid api key" });
|
|
414
|
+
|
|
415
|
+
const client: Client = createClient({
|
|
416
|
+
key: "chp_unauthorized_key",
|
|
417
|
+
retries: 3,
|
|
418
|
+
flushDelay: 10000,
|
|
419
|
+
logLevel: LogLevel.Error,
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
try {
|
|
423
|
+
await client.log({ event: "auth.failed", value: 1 });
|
|
424
|
+
await client.flush();
|
|
425
|
+
await client.flush();
|
|
426
|
+
|
|
427
|
+
expect(mock.history.post.length).toBe(1);
|
|
428
|
+
expect(errorSpy).toHaveBeenCalledWith("Chirpier API returned 401: invalid api key");
|
|
429
|
+
} finally {
|
|
430
|
+
await client.shutdown();
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
test("does not retry 403 and logs the Chirpier response message", async () => {
|
|
435
|
+
const mock = new MockAdapter(axios);
|
|
436
|
+
const errorSpy = jest.spyOn(console, "error").mockImplementation(() => undefined);
|
|
437
|
+
mock.onPost(DEFAULT_API_ENDPOINT).replyOnce(403, { message: "project is disabled" });
|
|
438
|
+
|
|
439
|
+
const client: Client = createClient({
|
|
440
|
+
key: "chp_forbidden_key",
|
|
441
|
+
retries: 3,
|
|
442
|
+
flushDelay: 10000,
|
|
443
|
+
logLevel: LogLevel.Error,
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
try {
|
|
447
|
+
await client.log({ event: "auth.forbidden", value: 1 });
|
|
448
|
+
await client.flush();
|
|
449
|
+
await client.flush();
|
|
450
|
+
|
|
451
|
+
expect(mock.history.post.length).toBe(1);
|
|
452
|
+
expect(errorSpy).toHaveBeenCalledWith("Chirpier API returned 403: project is disabled");
|
|
453
|
+
} finally {
|
|
454
|
+
await client.shutdown();
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
test.each([404, 500, 503])( "does not retry non-retryable status %s", async (status) => {
|
|
459
|
+
const mock = new MockAdapter(axios);
|
|
460
|
+
mock.onPost(DEFAULT_API_ENDPOINT).replyOnce(status, { error: `http ${status}` });
|
|
461
|
+
|
|
462
|
+
const client: Client = createClient({
|
|
463
|
+
key: `chp_non_retryable_${status}`,
|
|
464
|
+
retries: 3,
|
|
465
|
+
flushDelay: 10000,
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
try {
|
|
469
|
+
await client.log({ event: `non.retryable.${status}`, value: 1 });
|
|
470
|
+
await client.flush();
|
|
471
|
+
await client.flush();
|
|
472
|
+
|
|
473
|
+
expect(mock.history.post.length).toBe(1);
|
|
474
|
+
} finally {
|
|
475
|
+
await client.shutdown();
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
test("retries 502 responses", async () => {
|
|
480
|
+
jest.useFakeTimers();
|
|
481
|
+
const mock = new MockAdapter(axios);
|
|
482
|
+
mock.onPost(DEFAULT_API_ENDPOINT).replyOnce(502, { error: "bad gateway" });
|
|
483
|
+
mock.onPost(DEFAULT_API_ENDPOINT).replyOnce(502, { error: "bad gateway" });
|
|
484
|
+
mock.onPost(DEFAULT_API_ENDPOINT).replyOnce(200, { success: true });
|
|
485
|
+
|
|
486
|
+
const client: Client = createClient({
|
|
487
|
+
key: "chp_bad_gateway_key",
|
|
488
|
+
retries: 2,
|
|
489
|
+
flushDelay: 10000,
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
try {
|
|
493
|
+
await client.log({ event: "bad.gateway", value: 1 });
|
|
494
|
+
const flushPromise = client.flush();
|
|
495
|
+
await jest.runAllTimersAsync();
|
|
496
|
+
await expect(flushPromise).resolves.toBeUndefined();
|
|
497
|
+
expect(mock.history.post.length).toBe(3);
|
|
498
|
+
} finally {
|
|
499
|
+
await client.shutdown();
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
test("flush requeues only retryable failures", async () => {
|
|
504
|
+
const retryableMock = new MockAdapter(axios);
|
|
505
|
+
retryableMock.onPost(DEFAULT_API_ENDPOINT).replyOnce(502, { error: "bad gateway" });
|
|
506
|
+
retryableMock.onPost(DEFAULT_API_ENDPOINT).replyOnce(200, { success: true });
|
|
507
|
+
|
|
508
|
+
const retryableClient: Client = createClient({
|
|
509
|
+
key: "chp_retryable_requeue_key",
|
|
510
|
+
retries: 0,
|
|
511
|
+
flushDelay: 10000,
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
try {
|
|
515
|
+
await retryableClient.log({ event: "retryable.requeue", value: 1 });
|
|
516
|
+
await retryableClient.flush();
|
|
517
|
+
await retryableClient.flush();
|
|
518
|
+
expect(retryableMock.history.post.length).toBe(2);
|
|
519
|
+
} finally {
|
|
520
|
+
await retryableClient.shutdown();
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
const nonRetryableMock = new MockAdapter(axios);
|
|
524
|
+
nonRetryableMock.onPost(DEFAULT_API_ENDPOINT).replyOnce(404, { error: "not found" });
|
|
525
|
+
|
|
526
|
+
const nonRetryableClient: Client = createClient({
|
|
527
|
+
key: "chp_non_retryable_requeue_key",
|
|
528
|
+
retries: 0,
|
|
529
|
+
flushDelay: 10000,
|
|
530
|
+
logLevel: LogLevel.None,
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
try {
|
|
534
|
+
await nonRetryableClient.log({ event: "non.retryable.drop", value: 1 });
|
|
535
|
+
await nonRetryableClient.flush();
|
|
536
|
+
await nonRetryableClient.flush();
|
|
537
|
+
expect(nonRetryableMock.history.post.length).toBe(1);
|
|
538
|
+
} finally {
|
|
539
|
+
await nonRetryableClient.shutdown();
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
|
|
344
543
|
test("getEventLogs uses servicer endpoint with period, limit, and offset", async () => {
|
|
345
544
|
const mock = new MockAdapter(axios);
|
|
346
545
|
mock.onGet("https://api.chirpier.co/v1.0/events/evt_123/logs?period=hour&limit=25&offset=10").reply(200, []);
|
package/src/index.ts
CHANGED
|
@@ -204,6 +204,99 @@ export class ChirpierError extends Error {
|
|
|
204
204
|
}
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
+
type LogRetryPolicy = "success" | "retryable" | "retry_after" | "non_retryable";
|
|
208
|
+
|
|
209
|
+
function classifyLogResponseStatus(status?: number): LogRetryPolicy {
|
|
210
|
+
if (status === undefined) {
|
|
211
|
+
return "success";
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (status === 429) {
|
|
215
|
+
return "retry_after";
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (status >= 500) {
|
|
219
|
+
if (status === 500 || status === 503) {
|
|
220
|
+
return "non_retryable";
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return "retryable";
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (status >= 400) {
|
|
227
|
+
return "non_retryable";
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return "success";
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function getChirpierResponseMessage(data: unknown): string | undefined {
|
|
234
|
+
if (typeof data === "string") {
|
|
235
|
+
const trimmed = data.trim();
|
|
236
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (data && typeof data === "object") {
|
|
240
|
+
const record = data as Record<string, unknown>;
|
|
241
|
+
if (typeof record.message === "string" && record.message.trim().length > 0) {
|
|
242
|
+
return record.message.trim();
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (typeof record.error === "string" && record.error.trim().length > 0) {
|
|
246
|
+
return record.error.trim();
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
try {
|
|
250
|
+
return JSON.stringify(data);
|
|
251
|
+
} catch {
|
|
252
|
+
return undefined;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return undefined;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function getRetryDelayMs(retryCount: number, error: unknown): number {
|
|
260
|
+
if (axios.isAxiosError(error) && error.response?.status === 429) {
|
|
261
|
+
const retryAfterHeader = error.response.headers?.["retry-after"];
|
|
262
|
+
const retryAfterSeconds = Number(retryAfterHeader);
|
|
263
|
+
if (Number.isFinite(retryAfterSeconds) && retryAfterSeconds >= 0) {
|
|
264
|
+
return retryAfterSeconds * 1000;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const baseDelay = Math.pow(2, retryCount) * 1000;
|
|
269
|
+
const jitter = Math.random() * 0.3 * baseDelay;
|
|
270
|
+
return baseDelay + jitter;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function normalizeSendLogsError(error: unknown, logLevel: LogLevel): unknown {
|
|
274
|
+
if (!axios.isAxiosError(error)) {
|
|
275
|
+
return error;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const status = error.response?.status;
|
|
279
|
+
if (classifyLogResponseStatus(status) !== "non_retryable") {
|
|
280
|
+
return error;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const responseMessage = getChirpierResponseMessage(error.response?.data);
|
|
284
|
+
if ((status === 401 || status === 403) && logLevel >= LogLevel.Error) {
|
|
285
|
+
if (responseMessage) {
|
|
286
|
+
console.error(`Chirpier API returned ${status}: ${responseMessage}`);
|
|
287
|
+
} else {
|
|
288
|
+
console.error(`Chirpier API returned ${status}`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const message = responseMessage ? `HTTP ${status}: ${responseMessage}` : `HTTP ${status}`;
|
|
293
|
+
return new ChirpierError(message, "NON_RETRYABLE_RESPONSE");
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function isNonRetryableLogError(error: unknown): error is ChirpierError {
|
|
297
|
+
return error instanceof ChirpierError && error.code === "NON_RETRYABLE_RESPONSE";
|
|
298
|
+
}
|
|
299
|
+
|
|
207
300
|
interface QueuedLog {
|
|
208
301
|
readonly log: Log;
|
|
209
302
|
readonly timestamp: number;
|
|
@@ -311,17 +404,15 @@ export class Client {
|
|
|
311
404
|
|
|
312
405
|
axiosRetry(this.axiosInstance, {
|
|
313
406
|
retries: this.retries,
|
|
314
|
-
retryDelay: (retryCount) =>
|
|
315
|
-
const baseDelay = Math.pow(2, retryCount) * 1000;
|
|
316
|
-
const jitter = Math.random() * 0.3 * baseDelay;
|
|
317
|
-
return baseDelay + jitter;
|
|
318
|
-
},
|
|
407
|
+
retryDelay: (retryCount, error) => getRetryDelayMs(retryCount, error),
|
|
319
408
|
retryCondition: (error) => {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
409
|
+
if (axiosRetry.isNetworkError(error)) {
|
|
410
|
+
return true;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
const status = error.response?.status;
|
|
414
|
+
const retryPolicy = classifyLogResponseStatus(status);
|
|
415
|
+
return retryPolicy === "retryable" || retryPolicy === "retry_after";
|
|
325
416
|
},
|
|
326
417
|
shouldResetTimeout: true,
|
|
327
418
|
});
|
|
@@ -466,6 +557,13 @@ export class Client {
|
|
|
466
557
|
console.error("Failed to send logs:", error);
|
|
467
558
|
}
|
|
468
559
|
|
|
560
|
+
if (isNonRetryableLogError(error)) {
|
|
561
|
+
if (this.logLevel >= LogLevel.Error) {
|
|
562
|
+
console.error("Dropping logs after non-retryable response from API");
|
|
563
|
+
}
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
|
|
469
567
|
await this.queueLock.acquire("logQueue", async () => {
|
|
470
568
|
this.logQueue = [...logsToSend, ...this.logQueue];
|
|
471
569
|
});
|
|
@@ -474,7 +572,11 @@ export class Client {
|
|
|
474
572
|
}
|
|
475
573
|
|
|
476
574
|
private async sendLogs(logs: Log[]): Promise<void> {
|
|
477
|
-
|
|
575
|
+
try {
|
|
576
|
+
await this.axiosInstance.post(this.apiEndpoint, logs);
|
|
577
|
+
} catch (error) {
|
|
578
|
+
throw normalizeSendLogsError(error, this.logLevel);
|
|
579
|
+
}
|
|
478
580
|
}
|
|
479
581
|
|
|
480
582
|
public async flush(): Promise<void> {
|