밤 늦게까지 여는 카페

Golang Effective Study for intermediate (3) 본문

For Fun/Go-lang

Golang Effective Study for intermediate (3)

Jㅐ둥이 2020. 12. 19. 14:58
반응형

goodahn.tistory.com/4

 

Golang Effective Study for intermediate (2)

실제로 프로그램을 만들면서 golang을 공부하는 시간을 가져보겠습니다. 제가 프로그램을 만들 때, 거치는 과정대로 서술하겠습니다. 본 글은 2020년 9월달부터 작성되었습니다. 슬랙 API 및 기능이

goodahn.tistory.com

이전 포스팅에서 간단하게 설계했던 알람프로그램을 실제로 구현해보는 시간을 갖겠습니다.

 

구현할 것들

github.com/goodahn/AlarmForProgrammer/issues/1

 

Prototype of alarming function · Issue #1 · goodahn/AlarmForProgrammer

test that monitoring command works well implement monitoring command function test that the function of "1" is managed well by config file implement monitoring config function implement r...

github.com

레포지토리의 이슈에도 정리한 것처럼 구현할 순서는 다음과 같습니다.

  1. 명령어 모니터링 기능이 제대로 기능하는지 확인하는 테스트 케이스 작성
  2. 명령어 모니터링 기능 구현
  3. 명령어 모니터링 기능이 설정 파일로 관리되는지 확인하는 테스트 케이스 작성
  4. 설정 파일을 파싱하는 기능 구현
  5. 명령어 모니터링 기능에 슬랙 web hook api 추가

구현 내용

1. 명령어 모니터링 기능을 위한 테스트 케이스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package alarm_test
import (
    "os/exec"
    "sync"
    "testing"
    "time"
    alarm "github.com/goodahn/AlarmForProgrammer"
    "github.com/stretchr/testify/require"
)
func TestMonitoringCommand(t *testing.T) {
    cmd := "test_monitoring_command"
    commandNum := 10
    m := alarm.NewCommandMonitor([]string{
        cmd,
    })
    m.SetMonitoringPeriod(100 * time.Millisecond)
    m.Start()
    time.Sleep(50 * time.Millisecond)
    wg := sync.WaitGroup{}
    for i := 0; i < commandNum; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            c := exec.Command("bash""test_monitoring_command.sh")
            err := c.Run()
            require.Nil(t, err)
        }()
    }
    wg.Wait()
    require.Equal(t, commandNum, m.TotalAlarmCount())
}
cs

 

빠른 테스트를 위해서 go routine을 이용해서 테스트 케이스 작성을 합니다.
하지만 생성된 go routine들이 언제 완료되는지 알 수가 없어
time.Sleep(60 * time.Second) 같은 코드를 삽입하고는 했습니다;;;
시간낭비를 해결하기 위해서 세마포어를 찾아보니 sync.WaitGroup이라고 좋은 게 있더라구요!

(참고: golang.org/pkg/sync/#example_WaitGroup)

 

2. 명령어 모니터링 기능 구현

github.com/goodahn/AlarmForProgrammer/blob/master/monitoring.go
 

goodahn/AlarmForProgrammer

Contribute to goodahn/AlarmForProgrammer development by creating an account on GitHub.

github.com

github.com/goodahn/AlarmForProgrammer/blob/master/process_info.go

map struct를 사용할 때, 자주 발생하는 실수 중 하나가 concurrent write일 것이라고 생각합니다.

Golang에서는 thread safety를 지키기 위해서 map struct에 concurrent write가 일어날 경우, panic이 발생합니다!

이번에는 concurrent write를 막기 위해서 sync.Mutex를 이용했습니다.

일반적인 lock처럼 Lock, Unlock을 통해서 mutual exclusion을 방지해줍니다.

(그 외에도 sync.RWMutex, sync.Mutex 도 있으니 한번 봐보시는 걸 추천드립니다.)

 

3. 명령어 모니터링 기능이 설정 파일로 관리되는지 확인하는 테스트 케이스 작성

4. 설정 파일을 파싱하는 기능 구현

 

기본적인 뼈대가 작성되어서 이제부터는 쉬운 작업이었습니다. CommandMonitor 생성자만 약간 수정해주는 것으로 마무리할 수 있었습니다.

 

5. 명령어 모니터링 기능에 슬랙 web hook api 추가

간단한 main.go + config 파일 작성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main
 
import (
        "path"
        "runtime"
        "time"
 
        alarm "github.com/goodahn/AlarmForProgrammer"
)
 
func main() {
        _, currentFilePath, _, _ := runtime.Caller(0)
        dirpath := path.Dir(currentFilePath)
 
        m := alarm.NewCommandMonitor(dirpath + "/../config.json")
        m.SetMonitoringPeriod(1 * time.Second)
        m.Start()
        for {
                time.Sleep(3 * time.Second)
        }
}
cs

18~20번째 줄은 프로그램이 종료되지 않도록 작성한 코드입니다.

프로그램이 종료되면 go routine이 자동적으로 소멸되기 때문에 추가하였습니다.

1
2
3
4
5
6
7
{
    "slackWebHookURL" : "https://hooks.slack.com/services/ASDFGHGH/QWER1234YUIUIO567809XZXCZV",
    "commandList" : [
        "go test"
    ]
}
 
cs

 

6. Manual Test

짠!

반응형