홈으로 돌아가기

.NET 데스크톱용 gRPC IPC: UI 로직 분리

이 기사는 gRPC와 IPC를 통해 UI와 비즈니스 로직을 분리한 .NET 데스크톱 애플리케이션 아키텍처를 설명합니다. Headless 백엔드가 안정성을 보장하고, thin client가 UX를 담당합니다. proto, Rx.NET 및 프로세스 수명 주기 예제.

.NET의 gRPC와 IPC: 모놀리스 없는 안정적인 데스크톱 아키텍처
Advertisement 728x90

gRPC와 IPC를 활용한 .NET 데스크톱 앱의 UI와 비즈니스 로직 분리

WPF나 Avalonia UI 데스크톱 애플리케이션에서는 비즈니스 로직이 UI 스레드와 긴밀하게 결합되어 있습니다. 렌더링이 멈추거나 XAML이 충돌하면 전체 시스템이 정지됩니다: 타이머가 초기화되고, API 요청이 중단되며, 상태가 손실됩니다. 이는 스마트 홈 관리, 프로세스 차단, 미디어 플레이어와 같은 백그라운드 작업에 치명적입니다.

해결책은 헤드리스 백엔드(Worker Service)와 얇은 클라이언트(UI)로 분리하는 것입니다. 이들은 서버 측 스트리밍을 지원하는 gRPC를 통해 통신하여 프로세스 독립성을 보장합니다.

아키텍처: 두 개의 프로세스, 안전한 통신

백엔드 (Axorith.Host) — .NET Worker Service로 빌드된 WinExe입니다. 담당 기능:

Google AdInline article slot
  • 세션 상태 저장.
  • 타이머 및 모듈 오케스트레이션.
  • Home Assistant, Spotify, ETW 프로세스 모니터링과의 통합.
  • Named Pipes를 통한 브라우저 관리.

유휴 상태 소비량: 20–30 MB RAM. UI와 독립적으로 자율적으로 실행됩니다.

프론트엔드 (Axorith.Client)는 ReactiveUI를 사용한 Avalonia UI입니다. 시각화와 입력만 담당합니다. 작업 관리자에서 UI를 종료해도 백엔드는 계속 실행됩니다.

레이어 의존성:

Google AdInline article slot
  • 클라이언트와 호스트는 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는 지연 없이 즉시 다시 그리기를 보장합니다.

Google AdInline article slot

폴링 방식 대비 장점:

  • 지연 없음(폴링 대신 푸시).
  • 효율적인 트래픽 사용.
  • 강력한 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

Advertisement 728x90

다음 읽기