Go 언어의 장점은 goroutine이라는 가벼운 thread를 기반으로 동적인 처리를 효율적으로 제공한다는 것이다. 그리고 채널 등을 통해 goroutine을 어렵지 않게 제어할 수 있지만, 별도로 프로세스를 실행하는 경우에는 통제가 어렵다.
실제 내부적으로 Maven이나 Gradle 빌드를 별도의 프로세스로 실행하는 경우에 해당 프로세스들이 중지되지 않는 경우들이 종종 발생한다. 이런 경우 내부적인 goroutine 관리만으로는 프로세스를 중지할 수 없다.
이런 경우에 친절하게도 Go에서는 타임아웃이 적용된 프로세스를 시작할 수 있고, 타임아웃이 된 경우에 실행했던 프로세스를 "kill -9"와 같은 명령으로 강제 종료시키는 것을 지원한다. 이를 공통 함수로 활용하면 어렵지 않게 타임아웃을 적용할 수 있다.
package util
import (
"context"
"errors"
"fmt"
"log"
"os/exec"
"runtime"
"time"
"golang.org/x/text/encoding/korean"
"golang.org/x/text/transform"
)
// Windows에서 한글 처리 (euc-kr -> utf-8)
func WindowsHangul(text string) (result string, err error) {
result, _, err = transform.String(korean.EUCKR.NewDecoder(), text)
return
}
func ExecCommandWithTimeout(errorOnTimeout bool, timeoutMin int, workingDirectory string, name string, arg ...string) (output string, timedOut bool, runError error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeoutMin) * time.Minute)
defer cancel()
cmd := exec.CommandContext(ctx, name, arg...)
cmd.Dir = workingDirectory
stdOutAndErr, err := cmd.CombineOutput()
if ctx.Err() == context.DeadlineExceeded {
timedOut = true
}
if runtime.GOOS == "windows" {
output, _ = WindowsHangul(string(stdOutAndErr))
} else {
output = string(stdOutAndErr)
}
if err != nil {
output = fmt.Sprintf("%s\nError : %v", output, err)
runError = err
}
// Timeout 발생 시, error 발생
if timedOut {
var resolvedError error
if runError == nil {
if errorOnTimeout {
runError = errors.New("timed out")
}
} else {
if !errorOnTimeout {
resolvedError = runError
runError = nil
}
}
output += "\n=====> The process requested to execute has timed out!!!"
output += fmt.Sprintln("\ntimed out process :", name, arg)
if resolvedError != nil {
output += fmt.Sprintln("Resolved error :", resolvedError)
}
log.Println("[WARN] timed out proess working dir. :", workingDirectory)
log.Println("[WARN] timed out process output :", output)
}
return
}
아울러, Windows에서의 한글 처리(euc-kr 결과를 utf-8로 변환)하는 함수도 포함하고 있다.
Written with ♥ by Vincent Han
'소소한 팁' 카테고리의 다른 글
Flutter(dart) https SSL 인증서 오류 (proxy, self-signed 인증서) (0) | 2022.05.11 |
---|---|
JetBrains IDE Terminal에서 vi 명령 모드(escape) 이동이 안되는 경우 설정 방법 (0) | 2021.05.26 |
IntelliJ IDEA에서 maven이 반영되지 않을 때... (0) | 2020.12.03 |
JSON to Go struct (0) | 2020.11.30 |
Generic Methods를 통해 Spring Bean을 casting 없이 처리하는 Utility 클래스 (0) | 2020.10.27 |