Go로 만드는 데몬(daemon) 프로세스 처리 레시피
안녕하세요, 여러분. 오늘은 데몬 프로세스를 만드는 방법에 대해 이야기해볼까 하는데요.
데몬(daemon) 프로세스란?
여러분은 어떤 종류의 데몬 프로세스를 작성하고 있나요?
여기서 다룰 데몬(daemon)은 백그라운드에서 계속 실행되는 프로세스를 의미하는데요.
오타에 주의해야 할 부분입니다. (저는 'deamon'이라고 잘못 쓰는 경우가 많더라고요.)
Go 언어는 그 독특한 특성 덕분에 다양한 작업을 간편하게 구현할 수 있는데요.
데몬 구현 예제를 통해 Go의 매력을 느낄 수 있을 것이라고 생각합니다.
혹시 여러분이 알고 있는 유용한 레시피가 있다면 공유해 주세요.
기본부터 시작해볼까요?
무한 반복 실행하기
아래 코드를 Go Playground에서 시도해보세요.
func main() {
timeout := 5 * time.Second
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
f := func() error { // 예시 작업
return nil
}
simple(ctx, f)
}
func simple(ctx context.Context, task func() error) {
for {
err := task()
if err != nil {
log.Printf("[ERROR] err: %v", err)
}
time.Sleep(500 * time.Millisecond)
}
}
컨텍스트를 활용한 타임아웃 설정하기
아래 코드를 Go Playground에서 실행해보세요.
func withTimeout(ctx context.Context, task func() error) {
child, childCancel := context.WithCancel(ctx)
defer childCancel()
for {
err := task()
if err != nil {
log.Printf("[ERROR] err: %v", err)
}
select {
case <-child.Done():
log.Printf("[DEBUG] timeout")
return
default:
time.Sleep(500 * time.Millisecond)
}
}
}
응용편
특정 시간에만 실행하기
아래 코드를 Go Playground에서 실행해보세요.
func runDaemon(ctx context.Context, f func(context.Context) error) {
daemonHour := "7-10"
waitDuration := 500 * time.Millisecond
for {
now := time.Now()
if len(daemonHour) != 0 { // 실행 시간 지정이 있을 때
isExec := isExecHour(now, daemonHour)
log.Printf("[DEBUG] 현재 시간 체크 now:%v, daemonHour:%s, isExec:%v", now, daemonHour, isExec)
if !isExec {
time.Sleep(1 * time.Minute)
continue
}
}
err := f(ctx)
if err != nil {
log.Printf("[ERROR] err:%v", err)
}
time.Sleep(waitDuration)
}
}
func isExecHour(now time.Time, dHour string) bool {
delimiter := "-"
dh := strings.Split(dHour, delimiter)
if len(dh) <= 1 {
return false
}
start, err := strconv.Atoi(dh[0])
if err != nil {
return false
}
end, err := strconv.Atoi(dh[1])
if err != nil {
return false
}
h := now.Hour()
if start <= h && h <= end {
return true
}
return false
}
정기적으로 처리하기 (이전 작업이 끝나지 않아도)
아래 코드를 Go Playground에서 실행해보세요.
func timeTicker(ctx context.Context, task func(context.Context) error) {
counter := 0
waitTime := 1 * time.Second
ticker := time.NewTicker(waitTime)
defer ticker.Stop()
child, childCancel := context.WithCancel(ctx)
defer childCancel()
for { // 데몬화하기 위한 무한 루프
select {
case t := <-ticker.C:
counter++
requestID := counter
log.Println("[DEBUG] 시작 taskNo=", requestID, "t=", t)
errCh := make(chan error, 1)
go func() { // 비블록 방식으로 작업 실행
errCh <- task(ctx)
}()
go func() {
// 에러 채널에서 요청 결과 대기
select {
case err := <-errCh:
if err != nil {
// 데몬 강제 종료
log.Println("[ERROR] ", err)
}
log.Println("[DEBUG] 종료 requestNo=", requestID)
}
}()
case <-child.Done():
return
}
}
}
여러분도 멋진 데몬(daemon) 프로세스를 즐기시길 바랍니다!
'Go' 카테고리의 다른 글
Go 언어의 제너릭: 코드 재사용성과 타입 안전성의 새로운 패러다임 (1) | 2024.10.06 |
---|---|
Go Concurrency vs. RxJS: 어떤 기술이 더 나을까? 커뮤니티 유저들의 다양한 의견을 알아봅시다! (1) | 2024.10.05 |
Go fmt.Scanner 완벽 가이드: 효율적인 데이터 파싱 기법 (0) | 2024.09.20 |
Go 이미지 생성: 완벽한 테스트 전략으로 버그 없는 코드 작성하기 (0) | 2024.09.20 |
Go로 작성된 로컬 파일 처리 CLI 도구 테스트 방법 3가지 (0) | 2024.09.20 |