Rule‐engine ‐세부기능 - nhnacademy-aiot3-4iren/4iren-wiki GitHub Wiki
룰엔진 기능 및 비기능 요구사항
룰은 단순 목록이 아니라 그래프(플로우) 구조다. START → 조건 노드 → (분기/OR 병합) → ALERT 노드로 연결한다.
1. 기능 요구사항
1.1 플로우 CRUD
- 플로우 생성 / 조회 / 수정 / 삭제
- 플로우 활성화 / 비활성화
- 플로우 유효성 검증 (진입점 단일성, 순환 참조 방지 — DFS 기반 사이클 탐지)
- 노드·엣지는 개별 API가 아니라 플로우 단위로 함께 저장한다. 수정 시 기존 노드·연결을 모두 교체하므로 노드 ID는 수정 전후로 유지되지 않는다.
1.2 플로우 스케줄
- 요일 및 시간대 범위를 지정해 플로우가 동작할 구간을 제한한다.
- 스케줄 등록 / 조회 / 삭제
1.3 템플릿
- 템플릿 CRUD
- 강의실이 보유한 측정 항목을 기준으로, 요구 항목을 모두 충족하는 템플릿만 추천한다.
- 템플릿 상세를 조회한 뒤 클라이언트가 플로우 생성 API로 다시 제출하는 방식이다. (서버 측 복사 전용 API는 없다)
1.4 노드 설정 검증
- 노드 타입별 설정값(JSON)의 유효성을 검증한다.
- 타입별 기본값을 내려주는 API는 제공하지 않는다.
1.5 노드 타입
| 구분 | 노드 | 설명 |
|---|---|---|
| 시작 | START | 플로우 진입점 |
| 조건 | THRESHOLD | 수신된 현재값과 임계치 비교 |
| 조건 | AVERAGE | 지정 구간 평균 비교 |
| 조건 | DURATION | 조건이 일정 시간 지속되었는지 판단 |
| 조건 | GRADIENT | 지정 구간 변화율 비교 |
| 논리 | OR | 여러 상위 분기 결과를 병합 |
| 액션 | ALERT | 텔레그램 알림 이벤트 발행 |
- 측정 항목: CO2, 온도, 습도, 조도, 기압, TVOC, 적외선
- 비교 연산자:
>,>=,<,<=,=,!=
1.6 플로우 실행
- RabbitMQ로 수신한 센서 데이터가 트리거가 된다. (주기 폴링·스케줄 평가 없음)
- 해당 강의실의 활성 플로우를 조회해(Redis 캐시) 스케줄 조건을 통과한 플로우만 실행한다.
- 센서 메시지 수신 시 TimeSeriesPreparationService가 AVERAGE/DURATION/GRADIENT 노드용 시계열 데이터를 Redis ZSet(
room:{id}:metric:{TYPE}:ts)에 자동 저장한다. - 실행은 START의 참(TRUE) 분기부터 시작하는 BFS 그래프 순회이며, 각 조건 노드의 판정 결과에 따라 TRUE 또는 FALSE 한쪽 분기만 진행한다.
- 선택되지 않은 분기는 하위 OR 노드의 입력을 BLOCKED로 표시해, 남은 입력만으로 판정 가능한 OR을 다시 평가한다.
- ALERT 노드는 순회 도중 인라인으로 실행된다.
1.7 알림 발행
- 알림 유형:
COMFORT_LIMIT_EXCEEDED(쾌적 범위 이탈),VENTILATION_RECOMMEND(환기 권장) — 유형은 ALERT 노드 설정에서 작성자가 선택한다. - 알림 이벤트를 RabbitMQ로 발행하며, 실제 텔레그램 발송은 Notification 서비스가 수행한다.
- 중복 발송 방지: ALERT 노드 ID + 조건 판정 결과 해시를 키로 Redis 락을 걸고, 노드에 설정된 쿨다운 시간 동안 재발행을 차단한다. (해시에 측정값 자체는 포함되지 않으므로, 같은 조건이면 값이 더 악화되어도 쿨다운 중에는 재발행하지 않는다)
1.8 권한
- 플로우 관련 API는
X-User-Id/X-User-Role헤더를 검증하고, Core에 해당 강의실 관리 권한을 조회해 OWNER·ADMIN만 허용한다.
2. 이 서비스가 하지 않는 것
- 기기 제어를 하지 않는다. 액션 노드는 ALERT 하나뿐이며 냉난방기 on/off 등 제어 명령 경로가 없다.
- 룰 간 우선순위·충돌 조정을 하지 않는다. 플로우에 우선순위 필드가 없고, 활성 플로우는 모두 독립적으로 동시에 실행된다. 같은 상황에 두 플로우가 걸리면 각각 알림을 발행한다.
- 실행 이력을 저장하지 않는다. 실행·오류는 로그로만 남고, 이력 테이블이 없다. 발송된 알림 이력은 Notification 서비스에 남는다.
- 센서 오작동 누적 탐지를 하지 않는다. 임계치 이탈 누적 카운트와 쿨다운은 Processing 서비스가 담당한다.
3. 비기능 요구사항
3.1 성능
- 강의실의 여러 플로우를 가상 스레드 기반으로 동시 실행한다.
- 메시지 리스너는 비동기로 룰 엔진 처리를 수행하되, 처리 완료 후 RabbitMQ ack를 한다.
- 강의실별 활성 플로우 조회는 Redis 캐시로 처리한다.
- 시계열 데이터는 Redis ZSet에 최대 1시간 보관 후 자동 정리된다.
3.2 신뢰성
- 알림 발행 실패 시 재시도하지 않는다. 로그를 남기고 중복 방지 락만 해제해, 다음 트리거에서 다시 발행될 수 있게 한다.
- 센서 수신 큐에는 DLQ를 구성한다.
- 플로우 실행 오류는 격리되어 한 플로우의 실패가 다른 플로우 실행에 영향을 주지 않는다.
3.3 확장성
- 노드 타입 추가가 용이한 구조 (실행기 레지스트리 기반)