Skip to content

Commit 3090d71

Browse files
authored
Merge pull request #1531 from rocket-admin/backend_controller_timeouts
timeouts reworking
2 parents 67e11f7 + e7ed7a9 commit 3090d71

File tree

31 files changed

+3674
-3642
lines changed

31 files changed

+3674
-3642
lines changed

backend/src/app.controller.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import { Controller, Get, Inject, UseInterceptors } from '@nestjs/common';
22
import { ApiTags } from '@nestjs/swagger';
33
import { UseCaseType } from './common/data-injection.tokens.js';
4+
import { Timeout } from './decorators/timeout.decorator.js';
45
import { InTransactionEnum } from './enums/index.js';
56
import { SentryInterceptor } from './interceptors/index.js';
67
import { IGetHello } from './use-cases-app/use-cases-app.interface.js';
78

89
@UseInterceptors(SentryInterceptor)
10+
@Timeout()
911
@Controller()
1012
@ApiTags('app')
1113
export class AppController {

backend/src/app.module.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
2-
import { APP_GUARD, APP_INTERCEPTOR } from '@nestjs/core';
2+
import { APP_GUARD } from '@nestjs/core';
33
import { ScheduleModule } from '@nestjs/schedule';
44
import { ThrottlerGuard, ThrottlerModule } from '@nestjs/throttler';
55
import { AppController } from './app.controller.js';
@@ -36,7 +36,7 @@ import { UserActionModule } from './entities/user-actions/user-action.module.js'
3636
import { UserSecretModule } from './entities/user-secret/user-secret.module.js';
3737
import { SignInAuditModule } from './entities/user-sign-in-audit/sign-in-audit.module.js';
3838
import { TableWidgetModule } from './entities/widget/table-widget.module.js';
39-
import { TimeoutInterceptor } from './interceptors/index.js';
39+
4040
import { SaaSGatewayModule } from './microservices/gateways/saas-gateway.ts/saas-gateway.module.js';
4141
import { SaasModule } from './microservices/saas-microservice/saas.module.js';
4242
import { AppLoggerMiddleware } from './middlewares/logging-middleware/app-logger-middlewate.js';
@@ -101,10 +101,6 @@ import { DashboardWidgetModule } from './entities/visualizations/dashboard-widge
101101
],
102102
controllers: [AppController],
103103
providers: [
104-
{
105-
provide: APP_INTERCEPTOR,
106-
useClass: TimeoutInterceptor,
107-
},
108104
{
109105
provide: APP_GUARD,
110106
useClass: ThrottlerGuard,

backend/src/decorators/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ export { BodyUuid } from './body-uuid.decorator.js';
77
export { QueryUuid } from './query-uuid.decorator.js';
88
export { BodyEmail } from './body-email.decorator.js';
99
export { QueryTableName } from './query-table-name.decorator.js';
10+
export { Timeout, TIMEOUT_KEY, TimeoutDefaults } from './timeout.decorator.js';
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { SetMetadata, applyDecorators, UseInterceptors } from '@nestjs/common';
2+
import { TimeoutInterceptor } from '../interceptors/timeout.interceptor.js';
3+
4+
export const TIMEOUT_KEY = 'custom_timeout';
5+
6+
export const TimeoutDefaults = {
7+
DEFAULT: 15000,
8+
DEFAULT_TEST: 200000,
9+
EXTENDED: 60000,
10+
EXTENDED_TEST: 300000,
11+
AI: 300000,
12+
AI_TEST: 600000,
13+
} as const;
14+
15+
export function Timeout(timeoutMs?: number): MethodDecorator & ClassDecorator {
16+
return applyDecorators(SetMetadata(TIMEOUT_KEY, timeoutMs), UseInterceptors(TimeoutInterceptor));
17+
}

backend/src/entities/ai/user-ai-requests-v2.controller.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { UseCaseType } from '../../common/data-injection.tokens.js';
1616
import { MasterPassword } from '../../decorators/master-password.decorator.js';
1717
import { QueryTableName } from '../../decorators/query-table-name.decorator.js';
1818
import { SlugUuid } from '../../decorators/slug-uuid.decorator.js';
19+
import { Timeout, TimeoutDefaults } from '../../decorators/timeout.decorator.js';
1920
import { UserId } from '../../decorators/user-id.decorator.js';
2021
import { InTransactionEnum } from '../../enums/in-transaction.enum.js';
2122
import { ConnectionEditGuard } from '../../guards/connection-edit.guard.js';
@@ -52,6 +53,7 @@ export class UserAIRequestsControllerV2 {
5253
@ApiBody({ type: RequestInfoFromTableBodyDTO })
5354
@ApiQuery({ name: 'tableName', required: true, type: String })
5455
@ApiQuery({ name: 'threadId', required: false, type: String })
56+
@Timeout(process.env.NODE_ENV !== 'test' ? TimeoutDefaults.AI : TimeoutDefaults.AI_TEST)
5557
@Post('/ai/v2/request/:connectionId')
5658
public async requestInfoFromTableWithAI(
5759
@SlugUuid('connectionId') connectionId: string,
@@ -93,6 +95,7 @@ export class UserAIRequestsControllerV2 {
9395
@ApiBody({ type: RequestInfoFromTableBodyDTO })
9496
@ApiQuery({ name: 'tableName', required: true, type: String })
9597
@ApiQuery({ name: 'threadId', required: false, type: String })
98+
@Timeout(process.env.NODE_ENV !== 'test' ? TimeoutDefaults.AI : TimeoutDefaults.AI_TEST)
9699
@Post('/ai/v3/request/:connectionId')
97100
public async requestInfoFromTableWithAIBedrock(
98101
@SlugUuid('connectionId') connectionId: string,
@@ -131,6 +134,7 @@ export class UserAIRequestsControllerV2 {
131134
description: 'AI settings and widgets creation job has been queued.',
132135
})
133136
@UseGuards(ConnectionEditGuard)
137+
@Timeout(process.env.NODE_ENV !== 'test' ? TimeoutDefaults.AI : TimeoutDefaults.AI_TEST)
134138
@Get('/ai/v2/setup/:connectionId')
135139
public async requestAISettingsAndWidgetsCreation(
136140
@SlugUuid('connectionId') connectionId: string,

backend/src/entities/api-key/api-key.controller.ts

Lines changed: 75 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -11,89 +11,91 @@ import { FoundApiKeyDto } from './application/dto/found-api-key.dto.js';
1111
import { ICreateApiKey, IDeleteApiKey, IGetApiKey, IGetApiKeys } from './use-cases/api-key-use-cases.interface.js';
1212
import { buildCreatedApiKeyDto } from './utils/build-created-api-key.dto.js';
1313
import { buildFoundApiKeyDto } from './utils/build-found-api-key.dto.js';
14+
import { Timeout } from '../../decorators/timeout.decorator.js';
1415

1516
@UseInterceptors(SentryInterceptor)
17+
@Timeout()
1618
@Controller()
1719
@ApiBearerAuth()
1820
@ApiTags('Api Key')
1921
@Injectable()
2022
export class ApiKeyController {
21-
constructor(
22-
@Inject(UseCaseType.CREATE_API_KEY)
23-
private readonly createApiKeyUseCase: ICreateApiKey,
24-
@Inject(UseCaseType.GET_API_KEYS)
25-
private readonly getApiKeysUseCase: IGetApiKeys,
26-
@Inject(UseCaseType.GET_API_KEY)
27-
private readonly getApiKeyUseCase: IGetApiKey,
28-
@Inject(UseCaseType.DELETE_API_KEY)
29-
private readonly deleteApiKeyUseCase: IDeleteApiKey,
30-
) {}
23+
constructor(
24+
@Inject(UseCaseType.CREATE_API_KEY)
25+
private readonly createApiKeyUseCase: ICreateApiKey,
26+
@Inject(UseCaseType.GET_API_KEYS)
27+
private readonly getApiKeysUseCase: IGetApiKeys,
28+
@Inject(UseCaseType.GET_API_KEY)
29+
private readonly getApiKeyUseCase: IGetApiKey,
30+
@Inject(UseCaseType.DELETE_API_KEY)
31+
private readonly deleteApiKeyUseCase: IDeleteApiKey,
32+
) {}
3133

32-
@ApiOperation({ summary: 'Create new API key' })
33-
@ApiResponse({
34-
status: 200,
35-
description: 'Api key created.',
36-
type: CreatedApiKeyDto,
37-
})
38-
@Post('/apikey')
39-
public async createApiKey(@UserId() userId: string, @Body() apiKeyData: CreateApiKeyDto): Promise<CreatedApiKeyDto> {
40-
const apiKey = await this.createApiKeyUseCase.execute(
41-
{
42-
userId,
43-
title: apiKeyData.title,
44-
},
45-
InTransactionEnum.ON,
46-
);
47-
return buildCreatedApiKeyDto(apiKey);
48-
}
34+
@ApiOperation({ summary: 'Create new API key' })
35+
@ApiResponse({
36+
status: 200,
37+
description: 'Api key created.',
38+
type: CreatedApiKeyDto,
39+
})
40+
@Post('/apikey')
41+
public async createApiKey(@UserId() userId: string, @Body() apiKeyData: CreateApiKeyDto): Promise<CreatedApiKeyDto> {
42+
const apiKey = await this.createApiKeyUseCase.execute(
43+
{
44+
userId,
45+
title: apiKeyData.title,
46+
},
47+
InTransactionEnum.ON,
48+
);
49+
return buildCreatedApiKeyDto(apiKey);
50+
}
4951

50-
@ApiOperation({ summary: 'Get all user api keys' })
51-
@ApiResponse({
52-
status: 200,
53-
description: 'Get all user api keys.',
54-
type: FoundApiKeyDto,
55-
isArray: true,
56-
})
57-
@Get('/apikeys')
58-
public async getApiKeys(@UserId() userId: string): Promise<Array<FoundApiKeyDto>> {
59-
const foundApiKeys = await this.getApiKeysUseCase.execute(userId);
60-
return foundApiKeys.map((apiKey) => buildFoundApiKeyDto(apiKey));
61-
}
52+
@ApiOperation({ summary: 'Get all user api keys' })
53+
@ApiResponse({
54+
status: 200,
55+
description: 'Get all user api keys.',
56+
type: FoundApiKeyDto,
57+
isArray: true,
58+
})
59+
@Get('/apikeys')
60+
public async getApiKeys(@UserId() userId: string): Promise<Array<FoundApiKeyDto>> {
61+
const foundApiKeys = await this.getApiKeysUseCase.execute(userId);
62+
return foundApiKeys.map((apiKey) => buildFoundApiKeyDto(apiKey));
63+
}
6264

63-
@ApiOperation({ summary: 'Get api key by id' })
64-
@ApiResponse({
65-
status: 200,
66-
description: 'Get api key by id.',
67-
type: FoundApiKeyDto,
68-
})
69-
@Get('/apikey/:apiKeyId')
70-
public async getApiKey(@UserId() userId: string, @SlugUuid('apiKeyId') apiKeyId: string): Promise<FoundApiKeyDto> {
71-
const foundApiKey = await this.getApiKeyUseCase.execute({ userId, apiKeyId });
72-
return buildFoundApiKeyDto(foundApiKey);
73-
}
65+
@ApiOperation({ summary: 'Get api key by id' })
66+
@ApiResponse({
67+
status: 200,
68+
description: 'Get api key by id.',
69+
type: FoundApiKeyDto,
70+
})
71+
@Get('/apikey/:apiKeyId')
72+
public async getApiKey(@UserId() userId: string, @SlugUuid('apiKeyId') apiKeyId: string): Promise<FoundApiKeyDto> {
73+
const foundApiKey = await this.getApiKeyUseCase.execute({ userId, apiKeyId });
74+
return buildFoundApiKeyDto(foundApiKey);
75+
}
7476

75-
@ApiOperation({ summary: 'Delete api key by id' })
76-
@ApiResponse({
77-
status: 200,
78-
description: 'Get api key by id.',
79-
type: FoundApiKeyDto,
80-
})
81-
@Delete('/apikey/:apiKeyId')
82-
public async deleteApiKey(@UserId() userId: string, @SlugUuid('apiKeyId') apiKeyId: string): Promise<FoundApiKeyDto> {
83-
const deletedApiKey = await this.deleteApiKeyUseCase.execute({ userId, apiKeyId }, InTransactionEnum.ON);
84-
return buildFoundApiKeyDto(deletedApiKey);
85-
}
77+
@ApiOperation({ summary: 'Delete api key by id' })
78+
@ApiResponse({
79+
status: 200,
80+
description: 'Get api key by id.',
81+
type: FoundApiKeyDto,
82+
})
83+
@Delete('/apikey/:apiKeyId')
84+
public async deleteApiKey(@UserId() userId: string, @SlugUuid('apiKeyId') apiKeyId: string): Promise<FoundApiKeyDto> {
85+
const deletedApiKey = await this.deleteApiKeyUseCase.execute({ userId, apiKeyId }, InTransactionEnum.ON);
86+
return buildFoundApiKeyDto(deletedApiKey);
87+
}
8688

87-
@ApiOperation({ summary: 'Check api key' })
88-
@ApiResponse({
89-
status: 200,
90-
description: 'Api key is valid.',
91-
})
92-
@Get('/check/apikey')
93-
public async checkApiKey(): Promise<any> {
94-
return {
95-
result: true,
96-
message: 'Api key is valid',
97-
};
98-
}
89+
@ApiOperation({ summary: 'Check api key' })
90+
@ApiResponse({
91+
status: 200,
92+
description: 'Api key is valid.',
93+
})
94+
@Get('/check/apikey')
95+
public async checkApiKey(): Promise<any> {
96+
return {
97+
result: true,
98+
message: 'Api key is valid',
99+
};
100+
}
99101
}

backend/src/entities/company-info/company-info.controller.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,10 @@ import { FoundCompanyWhiteLabelPropertiesRO } from './application/dto/found-comp
8787
import { PaidFeatureGuard } from '../../guards/paid-feature.guard.js';
8888
import { isTest } from '../../helpers/app/is-test.js';
8989
import { TurnstileService } from '../../shared/services/turnstile.service.js';
90+
import { Timeout } from '../../decorators/timeout.decorator.js';
9091

9192
@UseInterceptors(SentryInterceptor)
93+
@Timeout()
9294
@Controller('company')
9395
@ApiBearerAuth()
9496
@ApiTags('Company')

0 commit comments

Comments
 (0)