Skip to content

Commit

Permalink
fix: add retries for dnslink (#467)
Browse files Browse the repository at this point in the history
Hitting external services can be flaky as we see periodic failures
in CI for `ipfs.io` and friends so add a retry.
  • Loading branch information
achingbrain authored Mar 14, 2024
1 parent 2c71b6e commit adc5589
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 4 deletions.
5 changes: 2 additions & 3 deletions packages/ipns/src/dnslink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ async function recursiveResolveDnslink (domain: string, depth: number, dns: DNS,
throw new Error('recursion limit exceeded')
}

log('query %s for TXT and CNAME records', domain)
log('query %s for TXT records', domain)
const txtRecordsResponse = await dns.query(domain, {
...options,
types: [
Expand Down Expand Up @@ -76,9 +76,8 @@ async function recursiveResolveDnslink (domain: string, depth: number, dns: DNS,
}
}

// no dnslink records found, try CNAMEs
// see if there is a CNAME delegation
log('no DNSLink records found for %s, falling back to CNAME', domain)

const cnameRecordsResponse = await dns.query(domain, {
...options,
types: [
Expand Down
24 changes: 23 additions & 1 deletion packages/ipns/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ const HOUR = 60 * MINUTE

const DEFAULT_LIFETIME_MS = 24 * HOUR
const DEFAULT_REPUBLISH_INTERVAL_MS = 23 * HOUR
const DEFAULT_DNSLINK_RETRIES = 3

export type PublishProgressEvents =
ProgressEvent<'ipns:publish:start'> |
Expand Down Expand Up @@ -321,6 +322,13 @@ export interface ResolveDNSLinkOptions extends AbortOptions, ProgressOptions<Res
* @default 32
*/
maxRecursiveDepth?: number

/**
* Retry in case of transport error
*
* @default 3
*/
retries?: number
}

export interface RepublishOptions extends AbortOptions, ProgressOptions<RepublishProgressEvents | IPNSRoutingEvents> {
Expand Down Expand Up @@ -424,7 +432,21 @@ class DefaultIPNS implements IPNS {
}

async resolveDNSLink (domain: string, options: ResolveDNSLinkOptions = {}): Promise<ResolveResult> {
const dnslink = await resolveDNSLink(domain, this.dns, this.log, options)
let dnslink = ''
const retries = options.retries ?? DEFAULT_DNSLINK_RETRIES

for (let i = 0; i < retries; i++) {
try {
dnslink = await resolveDNSLink(domain, this.dns, this.log, options)
break
} catch (err) {
if (i === (retries - 1)) {
throw err
}

log.error('error resolving %s attempt %d of %d', domain, i + 1, retries, err)
}
}

return this.#resolve(dnslink, options)
}
Expand Down
17 changes: 17 additions & 0 deletions packages/ipns/test/resolve-dnslink.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,23 @@ describe('resolveDNSLink', () => {
expect(result.cid.toString()).to.equal('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn')
})

it('should retry on failure', async () => {
dns.query.withArgs('foobar.baz')
.rejects(new CodeError('Not found', 'ENODATA'))

dns.query.withArgs('_dnslink.foobar.baz')
.onFirstCall().rejects(new CodeError('Not found', 'ENODATA'))
.onSecondCall().resolves(dnsResponse([{
name: '_dnslink.foobar.baz.',
TTL: 60,
type: RecordType.TXT,
data: 'dnslink=/ipfs/QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn'
}]))

const result = await name.resolveDNSLink('foobar.baz', { nocache: true, offline: true })
expect(result.cid.toString()).to.equal('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn')
})

it('should handle bad records', async () => {
dns.query.withArgs('_dnslink.foobar.baz').resolves(dnsResponse([{
name: 'foobar.baz.',
Expand Down

0 comments on commit adc5589

Please sign in to comment.