Skip to content

Commit e47e612

Browse files
authored
fix: improve request cancellation to keep the s3Client queue low (#548)
1 parent 53cbaa7 commit e47e612

22 files changed

+187
-43
lines changed

src/app.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ const build = (opts: buildOpts = {}): FastifyInstance => {
5050
app.addSchema(schemas.authSchema)
5151
app.addSchema(schemas.errorSchema)
5252

53+
app.register(plugins.signals)
5354
app.register(plugins.tenantId)
5455
app.register(plugins.metrics({ enabledEndpoint: !isMultitenant }))
5556
app.register(plugins.tracing)

src/config.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ type StorageConfigType = {
2525
storageS3Endpoint?: string
2626
storageS3ForcePathStyle?: boolean
2727
storageS3Region: string
28+
storageS3ClientTimeout: number
29+
storageS3UploadTimeout: number
30+
storageS3DownloadTimeout: number
2831
isMultitenant: boolean
2932
jwtSecret: string
3033
jwtAlgorithm: string
@@ -274,6 +277,15 @@ export function getConfig(options?: { reload?: boolean }): StorageConfigType {
274277
getOptionalConfigFromEnv('STORAGE_S3_FORCE_PATH_STYLE', 'GLOBAL_S3_FORCE_PATH_STYLE') ===
275278
'true',
276279
storageS3Region: getOptionalConfigFromEnv('STORAGE_S3_REGION', 'REGION') as string,
280+
storageS3ClientTimeout: Number(
281+
getOptionalConfigFromEnv('STORAGE_S3_CLIENT_TIMEOUT') || `${1000 * 600}` // 10m
282+
),
283+
storageS3DownloadTimeout: Number(
284+
getOptionalConfigFromEnv('STORAGE_S3_DOWNLOAD_TIMEOUT') || `${1000 * 43200}` //12h
285+
),
286+
storageS3UploadTimeout: Number(
287+
getOptionalConfigFromEnv('STORAGE_S3_UPLOAD_TIMEOUT') || `${1000 * 1200}` // 20m
288+
),
277289

278290
// DB - Migrations
279291
dbAnonRole: getOptionalConfigFromEnv('DB_ANON_ROLE') || 'anon',

src/http/plugins/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ export * from './metrics'
99
export * from './xml'
1010
export * from './signature-v4'
1111
export * from './tracing'
12+
export * from './signals'

src/http/plugins/signals.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import fastifyPlugin from 'fastify-plugin'
2+
import { FastifyInstance } from 'fastify'
3+
4+
declare module 'fastify' {
5+
interface FastifyRequest {
6+
signals: {
7+
body: AbortController
8+
response: AbortController
9+
disconnect: AbortController
10+
}
11+
}
12+
}
13+
14+
export const signals = fastifyPlugin(
15+
async function (fastify: FastifyInstance) {
16+
fastify.addHook('onRequest', async (req, res) => {
17+
req.signals = {
18+
body: new AbortController(),
19+
response: new AbortController(),
20+
disconnect: new AbortController(),
21+
}
22+
23+
// Client terminated the request before the body was fully received
24+
res.raw.once('close', () => {
25+
req.signals.response.abort()
26+
27+
if (!req.signals.disconnect.signal.aborted) {
28+
req.signals.disconnect.abort()
29+
}
30+
})
31+
})
32+
33+
// Client terminated the request before the body was fully sent
34+
fastify.addHook('onRequestAbort', async (req) => {
35+
req.signals.body.abort()
36+
37+
if (!req.signals.disconnect.signal.aborted) {
38+
req.signals.disconnect.abort()
39+
}
40+
})
41+
},
42+
{ name: 'request-signals' }
43+
)

src/http/routes/object/getObject.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ async function requestHandler(
7878
key: s3Key,
7979
version: obj.version,
8080
download,
81+
signal: request.signals.disconnect.signal,
8182
})
8283
}
8384

src/http/routes/object/getPublicObject.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export default async function routes(fastify: FastifyInstance) {
6666
key: s3Key,
6767
version: obj.version,
6868
download,
69+
signal: request.signals.disconnect.signal,
6970
})
7071
}
7172
)

src/http/routes/object/getSignedObject.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ export default async function routes(fastify: FastifyInstance) {
9292
version: obj.version,
9393
download,
9494
expires: new Date(exp * 1000).toUTCString(),
95+
signal: request.signals.disconnect.signal,
9596
})
9697
}
9798
)

src/http/routes/render/renderAuthenticatedImage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export default async function routes(fastify: FastifyInstance) {
6161
key: s3Key,
6262
version: obj.version,
6363
download,
64+
signal: request.signals.disconnect.signal,
6465
})
6566
}
6667
)

src/http/routes/render/renderPublicImage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export default async function routes(fastify: FastifyInstance) {
6666
key: s3Key,
6767
version: obj.version,
6868
download,
69+
signal: request.signals.disconnect.signal,
6970
})
7071
}
7172
)

src/http/routes/render/renderSignedImage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ export default async function routes(fastify: FastifyInstance) {
9494
version: obj.version,
9595
download,
9696
expires: new Date(exp * 1000).toUTCString(),
97+
signal: request.signals.disconnect.signal,
9798
})
9899
}
99100
)

0 commit comments

Comments
 (0)