Skip to content

Commit

Permalink
fix(lambda-tiler): prevent unhandled promise rejections when the reje…
Browse files Browse the repository at this point in the history
…ction is handled BM-1067 (#3329)

### Motivation

Fetching data from remote services can and will error on occasion, the
promises to fetch data from tiffs has two `.then()` one of the `.then()`
has a associated `.catch()` the other does not, this leads to a
`UnhandledPromiseRejection`

### Modifications

Do not use a `.then()` without `.catch()`

### Verification

Unit test addded.
also checked the code base for more usages of `void ....then()` without
.catch and they only occur in the landing page.
  • Loading branch information
blacha authored Aug 23, 2024
1 parent 1dfb33a commit 445da7f
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 21 deletions.
1 change: 0 additions & 1 deletion packages/lambda-tiler/src/routes/tile.xyz.raster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ export const TileXyzRaster = {
}

// Remove with typescript >=5.5.0

return (await Promise.all(toLoad)).filter((f) => f != null);
},

Expand Down
20 changes: 20 additions & 0 deletions packages/lambda-tiler/src/util/__test__/cache.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import assert from 'node:assert';
import { describe, it } from 'node:test';

import { fsa, FsMemory } from '@chunkd/fs';

import { SourceCache } from '../source.cache.js';

describe('CoSourceCache', () => {
it('should not exit if a promise rejection happens', async () => {
const cache = new SourceCache(5);

const mem = new FsMemory();
const tiffLoc = new URL('memory://foo/bar.tiff');
await mem.write(tiffLoc, Buffer.from('ABC123'));
fsa.register('memory://', mem);

await cache.getCog(tiffLoc).catch(() => null);
assert.equal(cache.cache.currentSize, 1);
});
});
28 changes: 8 additions & 20 deletions packages/lambda-tiler/src/util/source.cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,54 +7,42 @@ export type LruStrut = LruStrutCotar | LruStrutCog;
export interface LruStrutCotar {
type: 'cotar';
value: Promise<Cotar>;
_value?: Cotar;
size: number;
}

export interface LruStrutCog {
type: 'cog';
value: Promise<Tiff>;
_value?: Tiff;
}

class LruStrutObj<T extends LruStrut> {
ob: T;
constructor(ob: T) {
this.ob = ob;
if (this.ob._value == null) {
void this.ob.value.then((c) => (this.ob._value = c));
}
}

size = 1;
size: number;
}

export class SourceCache {
cache: SwappingLru<LruStrutObj<LruStrutCotar | LruStrutCog>>;
cache: SwappingLru<LruStrut>;
constructor(maxSize: number) {
this.cache = new SwappingLru<LruStrutObj<LruStrut>>(maxSize);
this.cache = new SwappingLru<LruStrut>(maxSize);
}

getCog(location: URL): Promise<Tiff> {
const existing = this.cache.get(location.href)?.ob;
const existing = this.cache.get(location.href);

if (existing != null) {
if (existing.type === 'cog') return existing.value;
throw new Error(`Existing object of type: ${existing.type} made for location: ${location.href}`);
}
const value = Tiff.create(fsa.source(location));
this.cache.set(location.href, new LruStrutObj({ type: 'cog', value }));
this.cache.set(location.href, { type: 'cog', value, size: 1 });
return value;
}

getCotar(location: URL): Promise<Cotar> {
const existing = this.cache.get(location.href)?.ob;
const existing = this.cache.get(location.href);

if (existing != null) {
if (existing.type === 'cotar') return existing.value;
throw new Error(`Existing object of type: ${existing.type} made for location: ${location.href}`);
}
const value = Cotar.fromTar(fsa.source(location));
this.cache.set(location.href, new LruStrutObj({ type: 'cotar', value }));
this.cache.set(location.href, { type: 'cotar', value, size: 1 });
return value;
}
}
Expand Down

0 comments on commit 445da7f

Please sign in to comment.