gRPC와 IPC를 활용한 .NET 데스크톱 앱의 UI와 비즈니스 로직 분리
WPF나 Avalonia UI 데스크톱 애플리케이션에서는 비즈니스 로직이 UI 스레드와 긴밀하게 결합되어 있습니다. 렌더링이 멈추거나 XAML이 충돌하면 전체 시스템이 정지됩니다: 타이머가 초기화되고, API 요청이 중단되며, 상태가 손실됩니다. 이는 스마트 홈 관리, 프로세스 차단, 미디어 플레이어와 같은 백그라운드 작업에 치명적입니다.
해결책은 헤드리스 백엔드(Worker Service)와 얇은 클라이언트(UI)로 분리하는 것입니다. 이들은 서버 측 스트리밍을 지원하는 gRPC를 통해 통신하여 프로세스 독립성을 보장합니다.
아키텍처: 두 개의 프로세스, 안전한 통신
백엔드 (Axorith.Host) — .NET Worker Service로 빌드된 WinExe입니다. 담당 기능:
- 세션 상태 저장.
- 타이머 및 모듈 오케스트레이션.
- Home Assistant, Spotify, ETW 프로세스 모니터링과의 통합.
- Named Pipes를 통한 브라우저 관리.
유휴 상태 소비량: 20–30 MB RAM. UI와 독립적으로 자율적으로 실행됩니다.
프론트엔드 (Axorith.Client)는 ReactiveUI를 사용한 Avalonia UI입니다. 시각화와 입력만 담당합니다. 작업 관리자에서 UI를 종료해도 백엔드는 계속 실행됩니다.
레이어 의존성:
- 클라이언트와 호스트는 Axorith.Contracts(gRPC proto)를 참조합니다.
- 세션 엔진을 위한 공유 코어.
- 유틸리티 및 플랫폼 종속 코드를 위한 공유.
- 모듈(플러그인)은 Sdk에 의존합니다.
반응성을 위한 서버 측 스트리밍 gRPC
gRPC는 protobuf 계약과 스트리밍을 위해 선택되었습니다. 설정 업데이트를 위한 Proto:
syntax = "proto3";
package axorith.contracts;
service ModulesService {
rpc StreamSettingUpdates (StreamSettingUpdatesRequest) returns (stream SettingUpdate);
}
message SettingUpdate {
string module_instance_id = 1;
string setting_key = 2;
SettingProperty property = 3;
oneof value {
string string_value = 4;
bool bool_value = 5;
int32 int_value = 6;
double number_value = 7;
ChoiceList choice_list = 8;
}
}
호스트 측: Rx.NET Subject를 사용한 SettingUpdateBroadcaster. 모듈의 변경사항(예: 트랙 전환)이 스트림으로 푸시됩니다.
클라이언트 측: 시작 시 스트림이 열리고, 업데이트는 ViewModel로 전달됩니다. ReactiveUI는 지연 없이 즉시 다시 그리기를 보장합니다.
폴링 방식 대비 장점:
- 지연 없음(폴링 대신 푸시).
- 효율적인 트래픽 사용.
- 강력한 protobuf 타이핑으로 동기화 오류 방지.
TCP 대신 안전한 IPC
로컬 포트는 취약합니다: 충돌, 바이러스 접근, 방화벽 팝업. IPC로 전환:
| 플랫폼 | 전송 방식 | ACL |
|-----------|-----------|-----|
| Windows | Named Pipes (ListenNamedPipe) | 현재 사용자만 |
| Linux/macOS | Unix Domain Sockets (ListenUnixSocket) | 파일 권한 |
호스트는 엔드포인트를 %AppData%/Axorith/host-info.json에 기록합니다. 클라이언트는 이를 읽고 연결합니다. 완전한 프로세스 격리.
라이프사이클과 UX
클라이언트 우선 접근 방식:
- Client.exe 실행.
- host-info.json 확인, 백그라운드에서 Host 자동 시작.
- 창 닫기 — 트레이로 최소화 (--tray 모드).
- 트레이 아이콘으로 Host 재시작/중지 또는 UI 복원.
연결 끊김 감지: HTTP/2 Keep-Alive로 스트림 중단 감지. 호스트는 시스템 알림(Windows Toast / D-Bus)을 전송합니다.
복원력 테스트:
- "작업" 세션: Spotify 재생 중, YouTube 차단.
- 작업 관리자에서 Client 종료.
- 결과: 백엔드 활성 상태 유지, 세션 지속.
구현 과제
- 계약: 모든 변경은 proto 재생성, 양쪽 업데이트 필요.
- 버전 관리: gRPC Interceptor가
x-axorith-version확인. 불일치 시 FailedPrecondition + 자동 업데이트. - 비동기 처리: 모든 호출은 Task 기반, localhost에서 타임아웃, 네트워크 오류 처리.
핵심 요약
- 프로세스 분리는 UI 스레드의 단일 장애점을 제거합니다.
- gRPC 스트리밍 + Rx.NET은 폴링 없이 반응형 UI를 제공합니다.
- IPC(Named Pipes/UDS)는 포트 없이 보안을 보장합니다.
- 클라이언트 우선 UX는 사용자에게 복잡성을 숨깁니다.
- 시스템 관리가 필요한 24/7 애플리케이션에 적합합니다.
— Editorial Team
아직 댓글이 없습니다.