Skip to content

Commit

Permalink
Merge pull request #99 from boostcampwm-2024/dev-back
Browse files Browse the repository at this point in the history
main merge
  • Loading branch information
hyo-limilimee authored Nov 16, 2024
2 parents cae5e56 + c903335 commit 3e53dd4
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 14 deletions.
13 changes: 13 additions & 0 deletions backend/console-server/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@ services:
image: nginx:latest
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- /etc/letsencrypt:/etc/letsencrypt
depends_on:
- server-blue
- server-green
networks:
- app-network

server-blue:
image: ghcr.io/boostcampwm-2024/web35-watchducks/backend/console-server:latest
Expand All @@ -24,6 +28,8 @@ services:
interval: 10s
timeout: 2s
retries: 5
networks:
- app-network

server-green:
image: ghcr.io/boostcampwm-2024/web35-watchducks/backend/console-server:latest
Expand All @@ -39,3 +45,10 @@ services:
interval: 10s
timeout: 2s
retries: 5
networks:
- app-network

networks:
app-network:
name: app-network
driver: bridge
16 changes: 16 additions & 0 deletions backend/console-server/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,24 @@ http {
server server-green:3002 backup;
}

# http를 https로 리디렉션
server {
listen 80;
server_name watchducks-test.store;

location / {
return 301 https://$host$request_uri;
}
}

server {
listen 443 ssl;
server_name watchducks-test.store;

ssl_certificate /etc/letsencrypt/live/watchducks-test.store/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/watchducks-test.store/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;

location / {
proxy_pass http://console_server;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const metricExpressions: Record<string, MetricFunction> = {
max: (metric: string) => `max(${metric}) as ${metric}`,
p95: (metric: string) => `quantile(0.95)(${metric}) as ${metric}`,
p99: (metric: string) => `quantile(0.99)(${metric}) as ${metric}`,
rate: (metric: string) => `(sum(${metric}) / count(*)) * 100 as ${metric}_rate`,
};

export type MetricAggregationType = keyof typeof metricExpressions;
34 changes: 30 additions & 4 deletions backend/console-server/src/log/log.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,34 @@ export class LogController {
async trafficRank() {
return await this.logService.trafficRank();
}
}

// 1. 기수 내 전체 프로젝트
// 2. 기수 내 총 트래픽
// 4. 기수 내 응답 성공률
@Get('/response-rate')
@HttpCode(HttpStatus.OK)
@ApiOperation({
summary: '기수 내 응답 성공률',
description: '요청받은 기수의 기수 내 응답 성공률를 반환합니다.',
})
@ApiResponse({
status: 200,
description: '기수 내 응답 성공률이 성공적으로 반환됨.',
type: ProjectResponseDto,
})
async responseSuccessRate() {
return await this.logService.responseSuccessRate();
}

@Get('/traffic')
@HttpCode(HttpStatus.OK)
@ApiOperation({
summary: '기수 내 총 트래픽',
description: '요청받은 기수의 기수 내 총 트래픽를 반환합니다.',
})
@ApiResponse({
status: 200,
description: '기수 내 총 트래픽가 정상적으로 반환됨.',
type: ProjectResponseDto,
})
async trafficByGeneration() {
return await this.logService.trafficByGeneration();
}
}
32 changes: 32 additions & 0 deletions backend/console-server/src/log/log.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,36 @@ export class LogRepository {

return await this.clickhouse.query(query, params);
}

async findResponseSuccessRate() {
const { query, params } = new TimeSeriesQueryBuilder()
.metrics([
{
name: 'is_error',
aggregation: 'rate',
},
])
.from('http_log')
.build();

const result = await this.clickhouse.query(query, params);
return {
success_rate: 100 - (result as Array<{ is_error_rate: number }>)[0].is_error_rate,
};
}

async findTrafficByGeneration() {
const { query, params } = new TimeSeriesQueryBuilder()
.metrics([
{
name: '*',
aggregation: 'count',
},
])
.from('http_log')
.build();

const result = await this.clickhouse.query(query, params);
return result[0];
}
}
12 changes: 12 additions & 0 deletions backend/console-server/src/log/log.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,16 @@ export class LogService {

return result.slice(0, 4);
}

async responseSuccessRate() {
const result = await this.logRepository.findResponseSuccessRate();

return result;
}

async trafficByGeneration() {
const result = await this.logRepository.findTrafficByGeneration();

return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,6 @@ import { ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer';

export class CountProjectByGenerationResponseDto {
@ApiProperty({
example: '5',
description: '부스트캠프 기수',
})
@Type(() => Number)
generation: number;

@ApiProperty({
example: '42',
description: '해당 기수의 프로젝트 총 개수',
Expand Down
1 change: 0 additions & 1 deletion backend/console-server/src/project/project.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ export class ProjectService {
});

return plainToInstance(CountProjectByGenerationResponseDto, {
generation: generation,
count: count,
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class DNSResponseBuilder {
name: question.name,
type: 'A',
class: 'IN',
ttl: 300,
ttl: 10,
data: this.config.proxyServerIp,
},
];
Expand Down
5 changes: 4 additions & 1 deletion backend/proxy-server/src/server/proxy-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ export class ProxyServer {
connections: Number(process.env.DEFAULT_CONNECTIONS),
pipelining: Number(process.env.DEFAULT_PIPELINING),
keepAliveTimeout: Number(process.env.DEFAULT_KEEP_ALIVE),
connect: {
rejectUnauthorized: false,
},
},
});
}
Expand Down Expand Up @@ -89,7 +92,7 @@ export class ProxyServer {
private async executeProxyRequest(request: FastifyRequest, reply: FastifyReply): Promise<void> {
const host = validateHost(request.headers[HOST_HEADER]);
const ip = await this.resolveDomain(host);
const targetUrl = buildTargetUrl(ip, request.url, 'http://'); // TODO: Protocol 별 arg 세팅
const targetUrl = buildTargetUrl(ip, request.url, 'https://'); // TODO: Protocol 별 arg 세팅

await this.sendProxyRequest(targetUrl, request, reply);
}
Expand Down

0 comments on commit 3e53dd4

Please sign in to comment.