출처: https://qiita.com/o-magari_kun/items/4cdfda0e9d00cbad3160
gocron을 사용하여 작업 스케줄링 수행
Go의 태스크 스케줄 라이브러리는 몇 개 존재하지만, 무한 루프 등으로 대기 상태를 구현할 필요가 없는 gocron을 선택했다.
Go 버전은 1.17.6
main.go
package main
import ( "fmt" "path/filepath"
"github.com/go-co-op/gocron" "github.com/joho/godotenv" )
func funcA() { fmt.Println("A") } func funcB() { fmt.Println("B") } func funcC() { fmt.Println("C") }
func main() { err := godotenv.Load(filepath.Join("path", "to", "dotenv", ".env")) if err != nil { panic("can't get .env") }
// gocron.Every(1).Day().At("00:40").Do(funcA) // gocron.Every(1).Saturday().At("11:15").Do(funcB) // gocron.Every(30).Minutes().Do(funcC) // <-gocron.Start()
scheduler := gocron.NewScheduler(time.Local) scheduler.Every(1).Day().At("00:40").Do(funcA) //1일 1회 0시 40분에 scheduler.Every(2).Saturday().At("11:15").Do(funcB)// 2주동안에 1회 토요일 11:15에 scheduler.Every(30).Minutes().Do(funcC) // 30분에 1회 scheduler.StartBlocking() } |
서두의 godotenv에 대해서는 후술. 이 샘플 코드의 시점에서는 불필요.
작성한 태스크 스케줄러를 데몬화
샘플 코드를 실행하면 알겠지만, 이 구현은 항상 프로그램을 실행해 두어야 한다.
그래서 바이너리로 컴파일한 것을 사용하여 데몬화를 시도한다.
우선은 바이너리를 작성한다.
go build -o go_cron main.go
다음으로 데몬화이지만, 이번은 툴을 사용하지 않고 CentOS의 systemd에 service를 추가한다.
cd /etc/systemd/system vi go_cron.service |
go_cron.service
[Unit] Description=golang cron tool ConditionPathExists=/path/to/go_cron
[Service] User=root Type=simple ExecStart=/path/to/go_cron/go_cron Restart=on-failure TimeoutStartSec=300
[Install] WantedBy=/path/to/wantedby |
ExecStart에 방금 만든 바이너리를 설정한다.
개인적으로 삽질한 부분으로는
- Restart = on-failure를 Restart = no로 설정하면 panic 등으로 go가 크래시 될 때 서비스가 죽었다. on-failure로 하는 것으로 서비스는 죽지 않았다.
- WantedBy를 설정하지 않으면 static 서비스가 된다. 이것을 설정하는 것으로 systemctl enable를 할 수 있게 된다.
.service 파일을 작성한 후 systemd에 변경 사항을 반영
systemctl daemon-reload
서비스 시작
systemctl start go_cron.service
# ステータス確認 systemctl status go_cron.service
go_cron.service - golang cron tool Loaded: loaded (/etc/systemd/system/go_cron.service; disabled; vendor preset: disabled) Active: active (running) since 火 2022-03-01 13:15:56 JST; 2h 27min ago |
Go 소스 코드에서 환경 변수를 사용할 위치가 있는 경우
서비스가 시작했다! 그리고 작업이 시작되기를 기다리고 있었지만 동작하지 않았다.
이럴 때는 journalctl 라는 명령으로 로그를 볼 수 있다.
sudo journalctl | grep go_cron
로그를 보면 Go의 처리가 내부에서 panic을 일으키고 있었다.
환경 변수를 사용하는 곳을 출력해 보면, 빈 공란이 출력되었다.
그래서 godotenv 패키지를 이용하여 .env 파일의 환경 변수를 사전에 취득하여 무사히 동작했다. 서두의 main.go 소스의 첫 3행은 이러한 이유이다.