Skip to content

Commit 4e1c7d0

Browse files
committed
feat: 분산 서비스 디테일하게 수정
1 parent 95679f8 commit 4e1c7d0

File tree

12 files changed

+795
-14
lines changed

12 files changed

+795
-14
lines changed

ProjectVG.Api/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
}
3939

4040
builder.Services.AddInfrastructureServices(builder.Configuration);
41-
builder.Services.AddApplicationServices();
41+
builder.Services.AddApplicationServices(builder.Configuration);
4242
builder.Services.AddDevelopmentCors();
4343

4444
// 부하테스트 환경에서 성능 모니터링 서비스 추가

ProjectVG.Api/appsettings.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,12 @@
1010
"JWT": {
1111
"Issuer": "ProjectVG",
1212
"Audience": "ProjectVG"
13+
},
14+
"DistributedSystem": {
15+
"Enabled": false,
16+
"ServerId": "api-server-001",
17+
"HeartbeatIntervalSeconds": 30,
18+
"CleanupIntervalMinutes": 5,
19+
"ServerTimeoutMinutes": 2
1320
}
1421
}

ProjectVG.Application/ApplicationServiceCollectionExtensions.cs

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Microsoft.Extensions.DependencyInjection;
2+
using Microsoft.Extensions.Configuration;
23
using ProjectVG.Application.Services.Auth;
34
using ProjectVG.Application.Services.Character;
45
using ProjectVG.Application.Services.Chat;
@@ -12,12 +13,14 @@
1213
using ProjectVG.Application.Services.Credit;
1314
using ProjectVG.Application.Services.Users;
1415
using ProjectVG.Application.Services.WebSocket;
16+
using ProjectVG.Application.Services.MessageBroker;
17+
using ProjectVG.Application.Services.Server;
1518

1619
namespace ProjectVG.Application
1720
{
1821
public static class ApplicationServiceCollectionExtensions
1922
{
20-
public static IServiceCollection AddApplicationServices(this IServiceCollection services)
23+
public static IServiceCollection AddApplicationServices(this IServiceCollection services, IConfiguration configuration)
2124
{
2225
// Auth Services
2326
services.AddScoped<IAuthService, AuthService>();
@@ -69,13 +72,34 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection
6972
// Conversation Services
7073
services.AddScoped<IConversationService, ConversationService>();
7174

72-
// Session Services
73-
services.AddSingleton<IConnectionRegistry, ConnectionRegistry>();
74-
75-
// WebSocket Services
76-
services.AddScoped<IWebSocketManager, WebSocketManager>();
75+
// Distributed System Services
76+
AddDistributedServices(services, configuration);
7777

7878
return services;
7979
}
80+
81+
/// <summary>
82+
/// 분산 시스템 관련 서비스 등록
83+
/// </summary>
84+
private static void AddDistributedServices(IServiceCollection services, IConfiguration configuration)
85+
{
86+
var distributedEnabled = configuration.GetValue<bool>("DistributedSystem:Enabled", false);
87+
88+
if (distributedEnabled)
89+
{
90+
// 분산 환경 서비스
91+
services.AddScoped<IMessageBroker, DistributedMessageBroker>();
92+
services.AddScoped<IWebSocketManager, DistributedWebSocketManager>();
93+
}
94+
else
95+
{
96+
// 단일 서버 환경 서비스
97+
services.AddScoped<IMessageBroker, LocalMessageBroker>();
98+
services.AddScoped<IWebSocketManager, WebSocketManager>();
99+
}
100+
101+
// WebSocket 연결 관리
102+
services.AddSingleton<IConnectionRegistry, ConnectionRegistry>();
103+
}
80104
}
81105
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
using System.Text.Json;
2+
3+
namespace ProjectVG.Application.Models.MessageBroker
4+
{
5+
public class BrokerMessage
6+
{
7+
public string MessageId { get; set; } = Guid.NewGuid().ToString();
8+
public string MessageType { get; set; } = string.Empty;
9+
public string? TargetUserId { get; set; }
10+
public string? TargetServerId { get; set; }
11+
public string? SourceServerId { get; set; }
12+
public DateTime Timestamp { get; set; } = DateTime.UtcNow;
13+
public string Payload { get; set; } = string.Empty;
14+
public Dictionary<string, string> Headers { get; set; } = new();
15+
16+
public static BrokerMessage CreateUserMessage(string userId, object payload, string? sourceServerId = null)
17+
{
18+
return new BrokerMessage
19+
{
20+
MessageType = "user_message",
21+
TargetUserId = userId,
22+
SourceServerId = sourceServerId,
23+
Payload = JsonSerializer.Serialize(payload),
24+
Headers = new Dictionary<string, string>
25+
{
26+
["content-type"] = "application/json"
27+
}
28+
};
29+
}
30+
31+
public static BrokerMessage CreateServerMessage(string serverId, object payload, string? sourceServerId = null)
32+
{
33+
return new BrokerMessage
34+
{
35+
MessageType = "server_message",
36+
TargetServerId = serverId,
37+
SourceServerId = sourceServerId,
38+
Payload = JsonSerializer.Serialize(payload),
39+
Headers = new Dictionary<string, string>
40+
{
41+
["content-type"] = "application/json"
42+
}
43+
};
44+
}
45+
46+
public static BrokerMessage CreateBroadcastMessage(object payload, string? sourceServerId = null)
47+
{
48+
return new BrokerMessage
49+
{
50+
MessageType = "broadcast_message",
51+
SourceServerId = sourceServerId,
52+
Payload = JsonSerializer.Serialize(payload),
53+
Headers = new Dictionary<string, string>
54+
{
55+
["content-type"] = "application/json"
56+
}
57+
};
58+
}
59+
60+
public T? DeserializePayload<T>()
61+
{
62+
try
63+
{
64+
return JsonSerializer.Deserialize<T>(Payload);
65+
}
66+
catch
67+
{
68+
return default;
69+
}
70+
}
71+
72+
public string ToJson()
73+
{
74+
return JsonSerializer.Serialize(this);
75+
}
76+
77+
public static BrokerMessage? FromJson(string json)
78+
{
79+
try
80+
{
81+
return JsonSerializer.Deserialize<BrokerMessage>(json);
82+
}
83+
catch
84+
{
85+
return null;
86+
}
87+
}
88+
}
89+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
namespace ProjectVG.Application.Models.Server
2+
{
3+
public class ServerInfo
4+
{
5+
public string ServerId { get; set; } = string.Empty;
6+
public DateTime StartedAt { get; set; }
7+
public DateTime LastHeartbeat { get; set; }
8+
public int ActiveConnections { get; set; }
9+
public string Status { get; set; } = "healthy";
10+
public string? Environment { get; set; }
11+
public string? Version { get; set; }
12+
13+
public ServerInfo()
14+
{
15+
}
16+
17+
public ServerInfo(string serverId)
18+
{
19+
ServerId = serverId;
20+
StartedAt = DateTime.UtcNow;
21+
LastHeartbeat = DateTime.UtcNow;
22+
ActiveConnections = 0;
23+
Status = "healthy";
24+
}
25+
26+
public void UpdateHeartbeat()
27+
{
28+
LastHeartbeat = DateTime.UtcNow;
29+
}
30+
31+
public void UpdateConnectionCount(int count)
32+
{
33+
ActiveConnections = count;
34+
}
35+
36+
public bool IsHealthy(TimeSpan timeout)
37+
{
38+
return DateTime.UtcNow - LastHeartbeat < timeout;
39+
}
40+
}
41+
}

ProjectVG.Application/Services/Chat/Handlers/ChatSuccessHandler.cs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,24 @@
22
using ProjectVG.Application.Models.WebSocket;
33
using ProjectVG.Application.Services.WebSocket;
44
using ProjectVG.Application.Services.Credit;
5+
using ProjectVG.Application.Services.MessageBroker;
56

67

78
namespace ProjectVG.Application.Services.Chat.Handlers
89
{
910
public class ChatSuccessHandler
1011
{
1112
private readonly ILogger<ChatSuccessHandler> _logger;
12-
private readonly IWebSocketManager _webSocketService;
13+
private readonly IMessageBroker _messageBroker;
1314
private readonly ICreditManagementService _tokenManagementService;
1415

1516
public ChatSuccessHandler(
1617
ILogger<ChatSuccessHandler> logger,
17-
IWebSocketManager webSocketService,
18+
IMessageBroker messageBroker,
1819
ICreditManagementService tokenManagementService)
1920
{
2021
_logger = logger;
21-
_webSocketService = webSocketService;
22+
_messageBroker = messageBroker;
2223
_tokenManagementService = tokenManagementService;
2324
}
2425

@@ -61,8 +62,14 @@ public async Task HandleAsync(ChatProcessContext context)
6162
var message = ChatProcessResultMessage.FromSegment(segment, requestId)
6263
.WithCreditInfo(tokensUsed, tokensRemaining);
6364
var wsMessage = new WebSocketMessage("chat", message);
64-
65-
await _webSocketService.SendAsync(userId, wsMessage);
65+
66+
_logger.LogInformation("[메시지브로커] 사용자에게 메시지 전송 시작: UserId={UserId}, MessageType={MessageType}, SegmentOrder={Order}, BrokerType={BrokerType}",
67+
userId, wsMessage.Type, segment.Order, _messageBroker.IsDistributed ? "Distributed" : "Local");
68+
69+
await _messageBroker.SendToUserAsync(userId, wsMessage);
70+
71+
_logger.LogInformation("[메시지브로커] 사용자에게 메시지 전송 완료: UserId={UserId}, MessageType={MessageType}, SegmentOrder={Order}",
72+
userId, wsMessage.Type, segment.Order);
6673
}
6774
catch (Exception ex)
6875
{

0 commit comments

Comments
 (0)