Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions redisinsight/api/config/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ export default {
},
redis_cloud: {
url: process.env.REDIS_CLOUD_URL || 'https://api-cloudapi.qa.redislabs.com/v1',
cloudDiscoveryTimeout: parseInt(process.env.RI_CLOUD_DISCOVERY_TIMEOUT, 10) || 60 * 1000, // 1 min
cloudDatabaseConnectionTimeout: parseInt(process.env.RI_CLOUD_DATABASE_CONNECTION_TIMEOUT, 10) || 30 * 1000,
},
redis_clients: {
idleSyncInterval: parseInt(process.env.CLIENTS_IDLE_SYNC_INTERVAL, 10) || 1000 * 60 * 60, // 1hr
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@ export class TimeoutInterceptor implements NestInterceptor {

private readonly message: string;

constructor(message: string = 'Request timeout') {
private readonly timeout: number;

constructor(message: string = 'Request timeout', timeoutMs?: number) {
this.message = message;
this.timeout = timeoutMs ?? serverConfig.requestTimeout;
}

intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(
timeout(serverConfig.requestTimeout),
timeout(this.timeout),
catchError((err) => {
if (err instanceof TimeoutError) {
const { method, url } = context.switchToHttp().getRequest();
Expand Down
1 change: 1 addition & 0 deletions redisinsight/api/src/constants/error-messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export default {
WRONG_DATABASE_TYPE: 'Wrong database type.',
CONNECTION_TIMEOUT:
'The connection has timed out, please check the connection details.',
SERVER_CLOSED_CONNECTION: 'Server closed the connection.',
AUTHENTICATION_FAILED: () => 'Failed to authenticate, please check the username or password.',
INCORRECT_DATABASE_URL: (url) => `Could not connect to ${url}, please check the connection details.`,
INCORRECT_CERTIFICATES: (url) => `Could not connect to ${url}, please check the CA or Client certificate.`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ export class CloudAutodiscoveryService {
password,
provider: HostingProvider.RE_CLOUD,
cloudDetails: database?.cloudDetails,
timeout: this.config.cloudDatabaseConnectionTimeout,
});

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ import {
GetCloudDatabasesDto,
} from 'src/modules/cloud/autodiscovery/dto';
import { CloudAuthHeaders } from 'src/modules/cloud/autodiscovery/decorators/cloud-auth.decorator';
import config from 'src/utils/config';

const cloudConf = config.get('redis_cloud');

@ApiTags('Cloud Autodiscovery')
@ApiHeaders([{
Expand All @@ -30,12 +33,12 @@ import { CloudAuthHeaders } from 'src/modules/cloud/autodiscovery/decorators/clo
name: 'x-cloud-api-secret',
}])
@UsePipes(new ValidationPipe({ transform: true }))
@UseInterceptors(new TimeoutInterceptor(undefined, cloudConf.cloudDiscoveryTimeout))
@Controller('cloud/autodiscovery')
export class CloudAutodiscoveryController {
constructor(private service: CloudAutodiscoveryService) {}

@Get('account')
@UseInterceptors(new TimeoutInterceptor())
@ApiEndpoint({
description: 'Get current account',
statusCode: 200,
Expand All @@ -53,7 +56,6 @@ export class CloudAutodiscoveryController {
}

@Get('subscriptions')
@UseInterceptors(new TimeoutInterceptor())
@ApiEndpoint({
description: 'Get information about current account’s subscriptions.',
statusCode: 200,
Expand Down Expand Up @@ -107,7 +109,6 @@ export class CloudAutodiscoveryController {
},
],
})
@UsePipes(new ValidationPipe({ transform: true }))
async addRedisCloudDatabases(
@CloudAuthHeaders() authDto: CloudAuthDto,
@Body() dto: AddCloudDatabasesDto,
Expand Down
15 changes: 14 additions & 1 deletion redisinsight/api/src/modules/redis/redis-connection.factory.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Redis, { Cluster, RedisOptions } from 'ioredis';
import { Injectable, Logger } from '@nestjs/common';
import { Injectable, InternalServerErrorException, Logger } from '@nestjs/common';
import { Database } from 'src/modules/database/models/database';
import apiConfig from 'src/utils/config';
import { ConnectionOptions } from 'tls';
Expand All @@ -10,6 +10,7 @@ import { ClientMetadata } from 'src/common/models';
import { ClusterOptions } from 'ioredis/built/cluster/ClusterOptions';
import { SshTunnelProvider } from 'src/modules/ssh/ssh-tunnel.provider';
import { TunnelConnectionLostException } from 'src/modules/ssh/exceptions';
import ERROR_MESSAGES from 'src/constants/error-messages';

const REDIS_CLIENTS_CONFIG = apiConfig.get('redis_clients');

Expand Down Expand Up @@ -195,6 +196,10 @@ export class RedisConnectionFactory {
this.logger.error('Failed connection to the redis database.', e);
reject(e);
});
connection.on('end', (): void => {
this.logger.error(ERROR_MESSAGES.SERVER_CLOSED_CONNECTION);
reject(new InternalServerErrorException(ERROR_MESSAGES.SERVER_CLOSED_CONNECTION));
});
connection.on('ready', (): void => {
this.logger.log('Successfully connected to the redis database');
resolve(connection);
Expand Down Expand Up @@ -241,6 +246,10 @@ export class RedisConnectionFactory {
this.logger.error('Failed connection to the redis oss cluster', e);
reject(!isEmpty(e.lastNodeError) ? e.lastNodeError : e);
});
cluster.on('end', (): void => {
this.logger.error(ERROR_MESSAGES.SERVER_CLOSED_CONNECTION);
reject(new InternalServerErrorException(ERROR_MESSAGES.SERVER_CLOSED_CONNECTION));
});
cluster.on('ready', (): void => {
this.logger.log('Successfully connected to the redis oss cluster.');
resolve(cluster);
Expand Down Expand Up @@ -271,6 +280,10 @@ export class RedisConnectionFactory {
this.logger.error('Failed connection to the redis oss sentinel', e);
reject(e);
});
client.on('end', (): void => {
this.logger.error(ERROR_MESSAGES.SERVER_CLOSED_CONNECTION);
reject(new InternalServerErrorException(ERROR_MESSAGES.SERVER_CLOSED_CONNECTION));
});
client.on('ready', (): void => {
this.logger.log('Successfully connected to the redis oss sentinel.');
resolve(client);
Expand Down