2 Commits
v1.0 ... v1.1

Author SHA1 Message Date
insulee
0f1ce38e64 fix: drift_monitor.py 정시읽기 절전 모드 대응 및 예외 안정성 개선
- services/drift_monitor.py
  - threading.Timer 체인 방식 → 폴링 루프 스레드로 교체
  - 30초 간격 폴링으로 절전 복귀 시 즉시 감지
  - _do_read()를 try/except로 감싸 예외 시에도 루프 유지
  - threading.Event로 깔끔한 중지 처리
  - _schedule_hourly(), _hourly_tick() 삭제 → _hourly_loop() 신규

- Dabit Time Manager.spec
  - 빌드 출력 파일명 v1.0 → v1.1 업데이트

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 09:06:41 +09:00
insulee
c4a71ea5fe chore: .gitattributes, .gitmessage 프로젝트 표준 설정 추가
- 줄바꿈 자동 관리 (.gitattributes)
- 커밋 메시지 규칙 템플릿 (.gitmessage)

파일: .gitattributes
- LF 강제: .py, .sh, .yml, Dockerfile
- CRLF 강제: .bat, .ps1

파일: .gitmessage
- feat/fix/docs/refactor/chore/perf/test 타입 규칙
- 70자 제목, 파일별 상세 섹션 필수

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 12:20:45 +09:00
4 changed files with 106 additions and 26 deletions

14
.gitattributes vendored Normal file
View File

@@ -0,0 +1,14 @@
# Auto-detect text files and normalize line endings
* text=auto
# Force LF for scripts and source files (Linux에서 실행되는 파일)
*.sh text eol=lf
*.py text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
*.env* text eol=lf
Dockerfile text eol=lf
# Force CRLF for Windows-only files
*.bat text eol=crlf
*.ps1 text eol=crlf

52
.gitmessage Normal file
View File

@@ -0,0 +1,52 @@
# <type>: <파일/컴포넌트> <제목> (70자 이내)
#
# <본문 - 변경 사항>
# - 항목1
# - 항목2
# - 항목3
#
# <파일별 상세 (필수)>
# 파일: <경로>
# - 변경 내용 1
# - 변경 내용 2
#
# <추가 컨텍스트/이유 (선택)>
#
# --- 커밋 규칙 ---
# Type:
# feat: 새 기능
# fix: 버그 수정
# docs: 문서 변경
# refactor: 리팩토링
# chore: 빌드/설정
# perf: 성능 개선
# test: 테스트
#
# 제목:
# - 70자 이내
# - 파일/컴포넌트 명시 (예: "admin.html", "logging_service.py", "관리자 페이지")
# - 명령형 ("추가", "수정")
# - 마침표 없음
# - 구체적으로
#
# 본문:
# - 불릿 포인트 사용
# - 무엇을, 왜 변경했는지
# - 파일별 상세 섹션 필수 (어떤 함수/클래스를 추가/수정했는지)
#
# 좋은 예시:
# feat: admin.html 세션 목록에 읽음 상태 뱃지 추가
#
# - localStorage 기반 세션 읽음 상태 관리
# - 읽지 않음 뱃지(빨강): 한 번도 클릭하지 않은 세션
# - 신규 메시지 뱃지(주황): 마지막 확인 이후 추가된 메시지 수
#
# 파일: apps/user_chatbot/static/admin.html
# - getSessionReadStatus() 함수 추가
# - markSessionAsRead() 함수 추가
# - getSessionBadges() 함수 추가
# - CSS: .badge-unread, .badge-new 스타일 추가
#
# 나쁜 예시:
# feat: 세션 목록에 뱃지 추가 (어느 파일인지 불명확)
# fix: 버그 수정 (무엇을 고쳤는지 불명확)

View File

@@ -22,7 +22,7 @@ exe = EXE(
a.binaries, a.binaries,
a.datas, a.datas,
[], [],
name='DabitTimeManager_v1.0', name='DabitTimeManager_v1.1',
debug=False, debug=False,
bootloader_ignore_signals=False, bootloader_ignore_signals=False,
strip=False, strip=False,

View File

@@ -16,7 +16,8 @@ class DriftMonitor:
def __init__(self): def __init__(self):
self._timer: threading.Timer | None = None self._timer: threading.Timer | None = None
self._hourly_timer: threading.Timer | None = None self._hourly_thread: threading.Thread | None = None
self._hourly_stop_event: threading.Event | None = None
self._running = False self._running = False
self._hourly_running = False self._hourly_running = False
self._interval = DEFAULT_MONITOR_INTERVAL self._interval = DEFAULT_MONITOR_INTERVAL
@@ -72,36 +73,49 @@ class DriftMonitor:
if self._hourly_running: if self._hourly_running:
return return
self._hourly_running = True self._hourly_running = True
self._schedule_hourly() self._hourly_stop_event = threading.Event()
self._hourly_thread = threading.Thread(target=self._hourly_loop, daemon=True)
self._hourly_thread.start()
def stop_hourly(self): def stop_hourly(self):
"""매시 정시 읽기 중지.""" """매시 정시 읽기 중지."""
self._hourly_running = False self._hourly_running = False
if self._hourly_timer: if self._hourly_stop_event:
self._hourly_timer.cancel() self._hourly_stop_event.set()
self._hourly_timer = None self._hourly_thread = None
def _schedule_hourly(self): def _hourly_loop(self):
"""다음 정시까지 대기 후 읽기 예약.""" """매시 정시 읽기 루프 (절전 복귀 대응)."""
if not self._hourly_running: while self._hourly_running:
return
now = datetime.now() now = datetime.now()
# 다음 정시: 현재 시 + 1, 분/초 = 0 next_hour = now.replace(minute=0, second=0, microsecond=0) + timedelta(hours=1)
next_hour = now.replace(minute=0, second=0, microsecond=0)
next_hour = next_hour + timedelta(hours=1) if self._on_error:
delay = (next_hour - now).total_seconds() delay = (next_hour - now).total_seconds()
if self._on_error: self._on_error(f"정시 읽기 예약: {next_hour.strftime('%H:%M:%S')} ({delay:.0f}초 후)")
self._on_error(f"정시 읽기 예약: {next_hour.strftime('%H:%M:%S')} ({delay:.0f}초 후)")
self._hourly_timer = threading.Timer(delay, self._hourly_tick) # 30초 간격 폴링으로 정시 대기 (절전 복귀 시 즉시 감지)
self._hourly_timer.daemon = True while self._hourly_running:
self._hourly_timer.start() now = datetime.now()
if now >= next_hour:
break
remaining = (next_hour - now).total_seconds()
wait = min(remaining, 30)
if self._hourly_stop_event.wait(timeout=wait):
return # 중지 요청
def _hourly_tick(self):
"""정시 도달 시 읽기 실행 후 다음 정시 예약."""
if not self._hourly_running: if not self._hourly_running:
return break
# 정시 읽기 실행
try:
self._do_read(schedule_next=False) self._do_read(schedule_next=False)
self._schedule_hourly() except Exception as e:
if self._on_error:
try:
self._on_error(f"정시 읽기 오류: {e}")
except:
pass
def read_once(self): def read_once(self):
"""즉시 한 번 읽기 (별도 스레드).""" """즉시 한 번 읽기 (별도 스레드)."""