Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
feat(icon): Retry loading hiccup resources.
Browse files Browse the repository at this point in the history
- internal issue: APM-310496 APM-282779
- nowadays CDNs are distributed systems that does not guarantees your request to reach right place. It started happening few hounders times per day for us that some icon couldn't be loaded
- CloudFront explicitly marks that requests *needs* to be retried
- mechanism is fairly simple, we retry any error from the server side (AWS throws 500 / 504 / 503 / 403)
  - 3 retries is enough for other resources we already handle
- docs: https://www.learnrxjs.io/learn-rxjs/operators/error_handling/retry

(cherry picked from commit f73b9f3)
  • Loading branch information
piotrl authored and nimrod13 committed Jul 12, 2021
1 parent 2aad849 commit 266afc5
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 1 deletion.
3 changes: 2 additions & 1 deletion libs/barista-components/icon/src/icon-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { HttpClient } from '@angular/common/http';
import { Inject, Injectable, Optional } from '@angular/core';
import { DtIconType } from '@dynatrace/barista-icons';
import { Observable, of } from 'rxjs';
import { finalize, map, share, tap } from 'rxjs/operators';
import { finalize, map, retry, share, tap } from 'rxjs/operators';

import { sanitizeSvg } from '@dynatrace/barista-components/core';

Expand Down Expand Up @@ -137,6 +137,7 @@ export class DtIconRegistry {
}

const req = this._httpClient.get(url, { responseType: 'text' }).pipe(
retry(3),
finalize(() => this._inProgressUrlFetches.delete(url)),
share(),
);
Expand Down
40 changes: 40 additions & 0 deletions libs/barista-components/icon/src/icon.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,46 @@ describe('DtIcon', () => {

expect(svgElement.querySelector('script')).toBeNull();
});

it('should retry when resources arent available', () => {
const fixture = createComponent(IconWithName);

fixture.componentInstance.iconName = 'xssInter';
fixture.detectChanges();
http.expectOne('xssInter.svg').error(new ErrorEvent('network error'), {});
// 1st retry
fixture.detectChanges();
http.expectOne('xssInter.svg').flush(FAKE_SVGS.xssMulti);

const iconElement =
fixture.debugElement.nativeElement.querySelector('dt-icon');
const svgElement = verifyAndGetSingleSvgChild(iconElement);

expect(svgElement.querySelector('script')).toBeNull();
});

it('should not show anything after 3 failed retries', () => {
const fixture = createComponent(IconWithName);

fixture.componentInstance.iconName = 'xssInter';
fixture.detectChanges();
http.expectOne('xssInter.svg').error(new ErrorEvent('network error'), {});
// 1st retry
fixture.detectChanges();
http.expectOne('xssInter.svg').error(new ErrorEvent('network error'), {});
// 2st retry
fixture.detectChanges();
http.expectOne('xssInter.svg').error(new ErrorEvent('network error'), {});
// 3st retry
fixture.detectChanges();
http.expectOne('xssInter.svg').error(new ErrorEvent('network error'), {});
fixture.detectChanges();

const iconElement =
fixture.debugElement.nativeElement.querySelector('dt-icon');

expect(iconElement.childNodes.length).toBe(0);
});
});

describe('DtIcon without config', () => {
Expand Down

0 comments on commit 266afc5

Please sign in to comment.