Skip to content

Commit a9e81ea

Browse files
committed
fix(aws/athena): destroy AWS SDK client on the 4 new athena routes
Cursor Bugbot finding: batch_get_query_execution, delete_named_query, list_databases, and list_table_metadata created an AthenaClient but never called client.destroy(), unlike every other new route in this PR. Wrapped each in try/finally to match.
1 parent 9870031 commit a9e81ea

4 files changed

Lines changed: 106 additions & 88 deletions

File tree

apps/sim/app/api/tools/athena/batch-get-query-execution/route.ts

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,40 +30,46 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
3030
secretAccessKey: data.secretAccessKey,
3131
})
3232

33-
const command = new BatchGetQueryExecutionCommand({
34-
QueryExecutionIds: data.queryExecutionIds,
35-
})
33+
try {
34+
const command = new BatchGetQueryExecutionCommand({
35+
QueryExecutionIds: data.queryExecutionIds,
36+
})
3637

37-
const response = await client.send(command)
38+
const response = await client.send(command)
3839

39-
return NextResponse.json({
40-
success: true,
41-
output: {
42-
queryExecutions: (response.QueryExecutions ?? []).map((execution) => ({
43-
queryExecutionId: execution.QueryExecutionId ?? '',
44-
query: execution.Query ?? null,
45-
state: execution.Status?.State ?? null,
46-
stateChangeReason: execution.Status?.StateChangeReason ?? null,
47-
statementType: execution.StatementType ?? null,
48-
database: execution.QueryExecutionContext?.Database ?? null,
49-
catalog: execution.QueryExecutionContext?.Catalog ?? null,
50-
workGroup: execution.WorkGroup ?? null,
51-
submissionDateTime: execution.Status?.SubmissionDateTime?.getTime() ?? null,
52-
completionDateTime: execution.Status?.CompletionDateTime?.getTime() ?? null,
53-
dataScannedInBytes: execution.Statistics?.DataScannedInBytes ?? null,
54-
engineExecutionTimeInMillis: execution.Statistics?.EngineExecutionTimeInMillis ?? null,
55-
queryPlanningTimeInMillis: execution.Statistics?.QueryPlanningTimeInMillis ?? null,
56-
queryQueueTimeInMillis: execution.Statistics?.QueryQueueTimeInMillis ?? null,
57-
totalExecutionTimeInMillis: execution.Statistics?.TotalExecutionTimeInMillis ?? null,
58-
outputLocation: execution.ResultConfiguration?.OutputLocation ?? null,
59-
})),
60-
unprocessedQueryExecutionIds: (response.UnprocessedQueryExecutionIds ?? []).map((item) => ({
61-
queryExecutionId: item.QueryExecutionId ?? null,
62-
errorCode: item.ErrorCode ?? null,
63-
errorMessage: item.ErrorMessage ?? null,
64-
})),
65-
},
66-
})
40+
return NextResponse.json({
41+
success: true,
42+
output: {
43+
queryExecutions: (response.QueryExecutions ?? []).map((execution) => ({
44+
queryExecutionId: execution.QueryExecutionId ?? '',
45+
query: execution.Query ?? null,
46+
state: execution.Status?.State ?? null,
47+
stateChangeReason: execution.Status?.StateChangeReason ?? null,
48+
statementType: execution.StatementType ?? null,
49+
database: execution.QueryExecutionContext?.Database ?? null,
50+
catalog: execution.QueryExecutionContext?.Catalog ?? null,
51+
workGroup: execution.WorkGroup ?? null,
52+
submissionDateTime: execution.Status?.SubmissionDateTime?.getTime() ?? null,
53+
completionDateTime: execution.Status?.CompletionDateTime?.getTime() ?? null,
54+
dataScannedInBytes: execution.Statistics?.DataScannedInBytes ?? null,
55+
engineExecutionTimeInMillis: execution.Statistics?.EngineExecutionTimeInMillis ?? null,
56+
queryPlanningTimeInMillis: execution.Statistics?.QueryPlanningTimeInMillis ?? null,
57+
queryQueueTimeInMillis: execution.Statistics?.QueryQueueTimeInMillis ?? null,
58+
totalExecutionTimeInMillis: execution.Statistics?.TotalExecutionTimeInMillis ?? null,
59+
outputLocation: execution.ResultConfiguration?.OutputLocation ?? null,
60+
})),
61+
unprocessedQueryExecutionIds: (response.UnprocessedQueryExecutionIds ?? []).map(
62+
(item) => ({
63+
queryExecutionId: item.QueryExecutionId ?? null,
64+
errorCode: item.ErrorCode ?? null,
65+
errorMessage: item.ErrorMessage ?? null,
66+
})
67+
),
68+
},
69+
})
70+
} finally {
71+
client.destroy()
72+
}
6773
} catch (error) {
6874
const errorMessage = getErrorMessage(error, 'Failed to batch get Athena query executions')
6975
logger.error('BatchGetQueryExecution failed', { error: errorMessage })

apps/sim/app/api/tools/athena/delete-named-query/route.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,22 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
3030
secretAccessKey: data.secretAccessKey,
3131
})
3232

33-
const command = new DeleteNamedQueryCommand({
34-
NamedQueryId: data.namedQueryId,
35-
})
33+
try {
34+
const command = new DeleteNamedQueryCommand({
35+
NamedQueryId: data.namedQueryId,
36+
})
3637

37-
await client.send(command)
38+
await client.send(command)
3839

39-
return NextResponse.json({
40-
success: true,
41-
output: {
40+
return NextResponse.json({
4241
success: true,
43-
},
44-
})
42+
output: {
43+
success: true,
44+
},
45+
})
46+
} finally {
47+
client.destroy()
48+
}
4549
} catch (error) {
4650
const errorMessage = getErrorMessage(error, 'Failed to delete Athena named query')
4751
logger.error('DeleteNamedQuery failed', { error: errorMessage })

apps/sim/app/api/tools/athena/list-databases/route.ts

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,25 +30,29 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
3030
secretAccessKey: data.secretAccessKey,
3131
})
3232

33-
const command = new ListDatabasesCommand({
34-
CatalogName: data.catalogName,
35-
...(data.workGroup && { WorkGroup: data.workGroup }),
36-
...(data.maxResults !== undefined && { MaxResults: data.maxResults }),
37-
...(data.nextToken && { NextToken: data.nextToken }),
38-
})
33+
try {
34+
const command = new ListDatabasesCommand({
35+
CatalogName: data.catalogName,
36+
...(data.workGroup && { WorkGroup: data.workGroup }),
37+
...(data.maxResults !== undefined && { MaxResults: data.maxResults }),
38+
...(data.nextToken && { NextToken: data.nextToken }),
39+
})
3940

40-
const response = await client.send(command)
41+
const response = await client.send(command)
4142

42-
return NextResponse.json({
43-
success: true,
44-
output: {
45-
databases: (response.DatabaseList ?? []).map((db) => ({
46-
name: db.Name ?? '',
47-
description: db.Description ?? null,
48-
})),
49-
nextToken: response.NextToken ?? null,
50-
},
51-
})
43+
return NextResponse.json({
44+
success: true,
45+
output: {
46+
databases: (response.DatabaseList ?? []).map((db) => ({
47+
name: db.Name ?? '',
48+
description: db.Description ?? null,
49+
})),
50+
nextToken: response.NextToken ?? null,
51+
},
52+
})
53+
} finally {
54+
client.destroy()
55+
}
5256
} catch (error) {
5357
const errorMessage = getErrorMessage(error, 'Failed to list Athena databases')
5458
logger.error('ListDatabases failed', { error: errorMessage })

apps/sim/app/api/tools/athena/list-table-metadata/route.ts

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -30,39 +30,43 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
3030
secretAccessKey: data.secretAccessKey,
3131
})
3232

33-
const command = new ListTableMetadataCommand({
34-
CatalogName: data.catalogName,
35-
DatabaseName: data.databaseName,
36-
...(data.expression && { Expression: data.expression }),
37-
...(data.workGroup && { WorkGroup: data.workGroup }),
38-
...(data.maxResults !== undefined && { MaxResults: data.maxResults }),
39-
...(data.nextToken && { NextToken: data.nextToken }),
40-
})
33+
try {
34+
const command = new ListTableMetadataCommand({
35+
CatalogName: data.catalogName,
36+
DatabaseName: data.databaseName,
37+
...(data.expression && { Expression: data.expression }),
38+
...(data.workGroup && { WorkGroup: data.workGroup }),
39+
...(data.maxResults !== undefined && { MaxResults: data.maxResults }),
40+
...(data.nextToken && { NextToken: data.nextToken }),
41+
})
4142

42-
const response = await client.send(command)
43+
const response = await client.send(command)
4344

44-
return NextResponse.json({
45-
success: true,
46-
output: {
47-
tables: (response.TableMetadataList ?? []).map((table) => ({
48-
name: table.Name ?? '',
49-
tableType: table.TableType ?? null,
50-
createTime: table.CreateTime?.getTime() ?? null,
51-
lastAccessTime: table.LastAccessTime?.getTime() ?? null,
52-
columns: (table.Columns ?? []).map((col) => ({
53-
name: col.Name ?? '',
54-
type: col.Type ?? null,
55-
comment: col.Comment ?? null,
56-
})),
57-
partitionKeys: (table.PartitionKeys ?? []).map((col) => ({
58-
name: col.Name ?? '',
59-
type: col.Type ?? null,
60-
comment: col.Comment ?? null,
45+
return NextResponse.json({
46+
success: true,
47+
output: {
48+
tables: (response.TableMetadataList ?? []).map((table) => ({
49+
name: table.Name ?? '',
50+
tableType: table.TableType ?? null,
51+
createTime: table.CreateTime?.getTime() ?? null,
52+
lastAccessTime: table.LastAccessTime?.getTime() ?? null,
53+
columns: (table.Columns ?? []).map((col) => ({
54+
name: col.Name ?? '',
55+
type: col.Type ?? null,
56+
comment: col.Comment ?? null,
57+
})),
58+
partitionKeys: (table.PartitionKeys ?? []).map((col) => ({
59+
name: col.Name ?? '',
60+
type: col.Type ?? null,
61+
comment: col.Comment ?? null,
62+
})),
6163
})),
62-
})),
63-
nextToken: response.NextToken ?? null,
64-
},
65-
})
64+
nextToken: response.NextToken ?? null,
65+
},
66+
})
67+
} finally {
68+
client.destroy()
69+
}
6670
} catch (error) {
6771
const errorMessage = getErrorMessage(error, 'Failed to list Athena table metadata')
6872
logger.error('ListTableMetadata failed', { error: errorMessage })

0 commit comments

Comments
 (0)