Skip to content

Commit

Permalink
perf(arns): cache resolution for non-existent name
Browse files Browse the repository at this point in the history
Without this it's easy for non-existent names to DOS the CUs we're using
to resolve names. This change caches non-existent name resolutions for 5
minutes in the in-memory/Redis cache.
  • Loading branch information
djwhitt committed Sep 20, 2024
1 parent 51b6748 commit 8a92d91
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 5 deletions.
4 changes: 2 additions & 2 deletions src/resolution/composite-arns-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export class CompositeArNSResolver implements NameResolver {
const cachedResolution: NameResolution = JSON.parse(
cachedResolutionBuffer.toString(),
);
resolution = cachedResolution; // hold on tho this in case we need it
resolution = cachedResolution; // hold on to this in case we need it
if (
cachedResolution !== undefined &&
cachedResolution.resolvedAt !== undefined &&
Expand All @@ -71,7 +71,7 @@ export class CompositeArNSResolver implements NameResolver {
name,
});
const resolution = await resolver.resolve(name);
if (resolution.resolvedId !== undefined) {
if (resolution.resolvedAt !== undefined) {
this.cache.set(name, Buffer.from(JSON.stringify(resolution)));
this.log.info('Resolved name', { name, resolution });
return resolution;
Expand Down
18 changes: 16 additions & 2 deletions src/resolution/on-demand-arns-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export class OnDemandArNSResolver implements NameResolver {
});
this.networkProcess = networkProcess;
this.ao = ao;
// TODO: use getRecords instead of getArNSRecord
this.aoCircuitBreaker = new CircuitBreaker(
({ name }: { name: string }) => {
return this.networkProcess.getArNSRecord({ name });
Expand All @@ -90,8 +91,21 @@ export class OnDemandArNSResolver implements NameResolver {
// find that name in the network process, using the circuit breaker if there are persistent AO issues
const arnsRecord = await this.aoCircuitBreaker.fire({ name: baseName });

if (arnsRecord === undefined || arnsRecord.processId === undefined) {
throw new Error('Invalid name, arns record not found');
if (arnsRecord === undefined) {
throw new Error('Unexpected undefined from CU');
}

if (

Check failure on line 98 in src/resolution/on-demand-arns-resolver.ts

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest)

Replace `⏎········arnsRecord·===·null·||⏎········arnsRecord.processId·===·undefined⏎······` with `arnsRecord·===·null·||·arnsRecord.processId·===·undefined`
arnsRecord === null ||
arnsRecord.processId === undefined
) {
return {
name,
resolvedId: undefined,
resolvedAt: Date.now(),
ttl: 300,
processId: undefined,
};
}

const processId = arnsRecord.processId;
Expand Down
15 changes: 14 additions & 1 deletion src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -596,15 +596,28 @@ export interface ValidNameResolution {
processId: string;
}

// Name resolved, but is missing
export interface MissingNameResolution {
name: string;
resolvedId: undefined;
resolvedAt: number;
ttl: number;
processId: undefined;
}

// An error occured while resolving the name
export interface FailedNameResolution {
name: string;
resolvedId: undefined;
resolvedAt: undefined;
ttl: undefined;
processId: undefined;
}

type NameResolution = ValidNameResolution | MissingNameResolution;
type NameResolution =
| ValidNameResolution
| MissingNameResolution
| FailedNameResolution;

export interface NameResolver {
resolve(name: string): Promise<NameResolution>;
Expand Down

0 comments on commit 8a92d91

Please sign in to comment.