Skip to content

Tags: modu-ai/mink

Tags

v0.2.2

Toggle v0.2.2's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
hotfix(scheduler): Stop() 동시성 sync.Mutex 보호 (W1, v0.2.2) (#146)

REVIEW-SCHEDULER-001-2026-05-10 W1 — Stop() 동시 호출 시
close-on-closed-channel panic + s.cron 무보호 포인터 race 수정.

## Reproduction (fix 전 캡처, count=20 -race)

panic: close of closed channel
goroutine 38 [running]:
github.com/modu-ai/goose/internal/ritual/scheduler.(*Scheduler).Stop(...)
    scheduler.go:349 +0x158
github.com/modu-ai/goose/internal/ritual/scheduler_test.TestStop_ConcurrentCalls_Safe.func1()
    scheduler_test.go:1350 +0x8c

scheduler.go:349 = close(s.workerDone). 기존 select { case <-workerDone: /
default: close(workerDone) } 가드는 두 goroutine이 동시에 default 분기로
진입할 수 있어 double-close panic.

## Fix

- Scheduler 구조체에 mu sync.Mutex 추가 (lifecycle 직렬화)
- Start()/Stop() 진입부 mutex lock + idempotent state 체크
- Stop(): state != Running이면 즉시 return (idempotent guard)
- close(workerDone) 가드 패턴 제거 (mutex 단일 진입 보장)
- s.cron 포인터도 mutex 보호 (atomic.Pointer 불필요)
- @mx:WARN 태그 추가 (lifecycle mutex 주의사항)

## 검증

- TestStop_ConcurrentCalls_Safe (count=10, -race): PASS
- TestStartStop_NoRace (count=10, -race): PASS
- full suite (count=1, -race): PASS (9.607s)
- full suite stress (count=10, -race): PASS (91.48s)
- go vet: PASS, gofmt: clean

## 변경 파일 (2개, +129 / -9)

- internal/ritual/scheduler/scheduler.go: mu mutex + Stop() 재작성
- internal/ritual/scheduler/scheduler_test.go: 50/20 goroutine
  reproduction tests 추가 (Go 1.25+ wg.Go 패턴)

SPEC: SPEC-GOOSE-SCHEDULER-001
REQ: REQ-SCHED-018 (graceful shutdown)
출처: REVIEW-SCHEDULER-001-2026-05-10 W1

🗿 MoAI <email@mo.ai.kr>