윈도우 서비스의 복구 동작 옵션 변경

 

윈도우 서비스는 프로그램 동작중에 예외가 발생하여 프로그램이 죽게 된 경우, 아래와 같은 Recovery 옵션이 있어 프로그램을 다시 시작하거나 (restart), 또는 전체 시스템을 리부팅하는 등의 대처를 자동으로 수행해 주는 옵션이 있다. 이 Recovery 옵션은 서비스 속성에서 설정 할 수 있는데, 속성에서 제공하는 것들을 잠깐 살펴보면 아래와 같다.

 

 

1. 다음기간 이후에 실패 횟수 다시설정

 

서비스는 에러가 발생하게 되면 이놈이 몇 번 째 에러인지 에러카운트를 올리는데, 여기에 설정 된 시간만큼 에러가 없으면 에러 카운트는 다시 0이 되어 새로운 에러가 발생하면 그 에러를 1번째 에러로 간주하여 첫째 실패에 대한 액션을 취하게 되는 식이다. 예를 들어 이 값이 30초로 (물론 속성창에서는 일 단위로만 가능하지만, 다른 방법을 통해 30초 설정이 가능함)설정되어 있다면, 아래와 같이 에러가 몇번 째 에러인지 세어 나가게 된다.

 

(error cnt : 0) - 에러 (error cnt : 1) - 10초 - 2번에러(error cnt : 2) - 30초

- (error cnt : 0) -  에러 (error cnt : 1) - 12초 - 에러 (error cnt : 2)

 

2. 다음 시간 이후에 서비스 다시 시작

 

에러가 발생하고 에러에 대한 대응 액션으로 서비스 다시 시작이 설정되어 있다면, 여기에 설정되어 있는 시간 만큼 에러 이후에 기다리고서 다시 서비스를 시작하게 된다.

 

그렇다. 그렇게 하면 된다. 그런데, 문제는 이게 아니다.

 

서비스 복구 옵션을 이렇게 사용자가 직접 정하는건 상당히 없어 보인다. 그게 문제다.

설치 패키지를 배포하고, 추가 설명으로 " 서비스 속성에 들어가서 어떻게 어떻게 하세요" 라고 적어놓는건 상당히 모양 빠지는 일이다.

 

그래서, 지금 개발하고 있는 C# windows service에서 이런 복구 옵션을 설정하여, 사용자가 할일이라고는 만들어놓은 설치 패키지를 더블 클릭하는 것 뿐이도록 만들어 보고자 구글링을 열심히 했다.

 

그런데 결론은 C# Windows service 프로젝트에는 이런 옵션 없ㅋ슴ㅋ.

ㅋㅋ..

 

물론 방법이 아예 없는 것은 아니다. 남들이 다 하는걸 못하는건 방법이 없어서가 아니라 내가 그냥 모르는 거라는 걸 다시한번 느꼈다. 그 방법은 크게 2가지로 나뉘는데 첫번째 방법은 "advapi32.dll의 함수를 C#에 import하여 사용하는 방법"이고 나머지 방법은 "sc.exe라는 콘솔 프로그램을 이용하여 윈도우 서비스의 속성을 변경하는 방법"이다.

 

전자에 나와 있는 방법 어떤 착한 턱수염 아저씨가 코드 프로젝트에잘 설명 해 놨다.

 

http://www.codeproject.com/KB/install/sercviceinstallerext.aspx?display=Print

 

그런데 좀 어렵다. serviceInstaller라는 클래스를 상속한 확장 클래스를 만드는데 자세한 사항을 공부하면 이편이 좀더 깔끔한 방식이 될 것 같기는 하다.

 

그러나 지금 서비스 프로그램은 64bit로 개발하고 있는데 외부에서 import한 라이브러리가 내가 알지 못하는 어떤 예외를 던질까 무서워 일단 이방법은 보류하고 나머지 sc.exe라는 프로그램을 이용하는 방법을 선택하기로 했다.

 

sc.exe가 32bit 든 64bit든 그냥 프로세스로 sc를 만들어 일반 콘솔에서 명령어 치듯 사용할 것이기 때문에 좀더 속편하게 쓸 수 있는 장점과 간단하다는 장점이 있는 방법이라 하겠다. 쓸 수 있는 기능면에서도 앞서 설명한 방법과 차이가 없다는 장점도 있다.

 

(참고로 sc.exe에 대한 자세한 아규먼트는 아래 문서를 참조하면 된다.)

http://technet.microsoft.com/en-us/library/cc754599.aspx

 

sc.exe는 서비스와 관련된 여러가지 작업을 할 수 있게 해주는 콘솔 프로그램으로서, fail에 대한 recovery를 설정하기 위해서는 failure라는 인자를 사용하여 아래와 같이원하는 서비스의 리커버리 옵션을 설정 할 수 있다.

 

 

failure에 대한 풀 옵션은 위에 있는 링크를 타고 들어가서 확인하면 되겠고..

위 콘솔창에 나와 잇는 정보만 살펴보자면 Envision_AES라는 서비스이름을 가지는 서비스를 마지막 에러를 기점으로 300초마다 error cnt를 0으로 재 설정하면서, 에러가 발생할 때 20000 ms의 지연을 가지고나서 서비스를 재 시작하도록 한다라는 의미를 가지고 있다.

 

이걸 InstallUtil.exe가 서비스를 설치하고나서 자동으로 설치되게 하려면 서비스의 serviceInstall가 가지는 이벤트 중에 Commited라는 이벤트의 콜백함수에다가 이 기능을 하는 코드를 입력해주면 된다. committed라는 이벤트는 설치가 모두 완료되면 발생하는 이벤트 쯤 되는 것 같다.

 

 

 

 

 

 

흐릿해서 잘 안보일 수도 있겠지만 간단히 설명하자면 Process 인스턴스를 하나 만들고 프로세스의 startinfo에 실행하고자 하는 프로그램이름인 sc 설정, 보이지 않는 hidden 프로세스로 설정, 그리고 아규먼트에 failure이후에 들어갈 값들을 지정하고 프로세스를 시작한 것 밖에 없다. "start()"

 

서비스 설치시 자동 시작

 

그런데 서비스를 installutil.exe로 설치하고 나면 서비스 시작 유형을 automatic으로 설정해 두었음에도 불구하고 서비스는 중지됨 상태로 있게 된다. 이것은 automatic이라는 의미가 "시스템이 부팅되었을 때 자동 시작됨"이기 때문이다. 설치는 했지만 컴퓨터가 리부팅 되지는 않았으니 어찌보면 당연한 말이기도 하다.

 

그래서 이번에는 서비스를 설치하자 마자 자동으로 서비스 프로그램을 프로세스로 만들어 실행시키는 구문을 만들어보고자 한다.

 

이것 또한 서비스 설치시 발생되는 committed 이벤트의 콜백함수에 집어 넣을 껀데, 사실 바로 위에 있는 그림파일에 이미 들어가 있다.

 

int exitCode 위에 있는 코드가 그것인데, 서비스 리커버리 옵션 고치는 것보다 오히려 코드는 간단하다. 서비스 실행을 관장하는 ServiceController의 인스턴스를 하나 만들고 (생성자 인수로 서비스의 이름을 받는다.) 서비스를 실행 " start() " 시키고, 서비스가 running 상태에 접어들기를 기다렸다가 ServicController를 닫는 " Close() " 과정밖에 없다.

 

간단하다.

 

Posted by 굿쟌
,