관리 메뉴

HAMA 블로그

예제로 보는 아카(akka) - 18. 서비스로 설치 ( Deploying ) 본문

Akka

예제로 보는 아카(akka) - 18. 서비스로 설치 ( Deploying )

[하마] 이승현 (wowlsh93@gmail.com) 2016. 12. 27. 14:15

- Scala 2.11.8 기반 

- Akka 2.4.11 기반 

- Java 8  (akka 2.4 부터는 java 8 요구함. scala 2.11 은 java 7도 괜찮지만~) 



서비스로 설치 ( Deploying )


이전 포스팅에 이어서 이번에는 서비스로 만드는 방식을 알아보겠습니다. 즉 서버가 시작하면 자동으로 시작되게 하고 , 이전까지는 ./helloakka 로 시작한 후에는 Ctrl+C 나 kill -9  pid 를 이용하여 적절한 리소스해제 없이 강제로 죽였어야 했는데요. 좀 더 우아하게 stop 시켜 봅시다. 


이전 포스팅에서 만든 프로젝트에서  이어서 해봅니다.

* 이전 포스팅과 마찬가지로 더 좋은 방법이 있을 수 있으며 적극적인 공유가 필요합니다.



이번 포스팅에서는 2가지를 합니다.


1. 서비스로 실행하기 ( 서버 내렸다가 다시 실행했을때 우리 서비스도 자동으로 실행되게) 

2. 시작,종료를 우아하게 처리하기  (이 부분은 정리가 좀 덜 됬습니다)




서비스로 실행하기


방법1.우분투에서 서비스로 등록하기 (nohup & 및 pkill 및 init.d 활용)


 프로젝트 폴더에 run 파일을 만들고 내용은 아래와 같이 합니다. 


#!/bin/sh


USERNAME=$USER

COMMAND="/home/hama/work/helloakka/stage/bin/helloakka"

KILL_COMMAND = "java -cp /home/hama/work/helloakka"

if [ "$1" = "start" ]; then

#check process

        # /dev/null 로 redirection 을 통해 화면 출력을 하지 않는것은 '표준출력' 에 한해서 해당된다. 

        #2>&1 는 표준에러를 표준출력으로 redirection 하라는 의미다.

pgrep -f  "java -cp /home/hama/work/helloakka"  > /dev/null 2>&1 # 0 이면 성공. 다른거면 실패 

if [$? -ne 0] ; then

#if not exists

echo "not exists"

else

#if exists

#pkill -f  "java -cp /home/hama/work/helloakka"

#echo "helloakka killed.."


echo "..exits.."

sleep 1

fi


nohup $COMMAND &

echo "helloakka Starting OK.."

elif [ "$1" = "stop" ]; then

pgrep -f  "java -cp /home/hama/work/helloakka"  > /dev/null 2>&1

if [ $? -ne 0 ] ; then

#if not exists

echo "helloakka process not found.."

else 

#if exists

pkill -f  "java -cp /home/hama/work/helloakka"

echo "helloakka killed.."

fi 


elif [ "$1" = "log" ]; then

tail -f logs/*.log

else

echo "usage run [start/stop/log]"

fi


run 을 실행하기 위해  .profile 파일에 export PATH=$PATH:.  추가

source .profile 


/etc/init.d 아래 스크립트 작성 (helloakka 이름) 

#! /bin/sh
# /etc/init.d/helloakka

### BEGIN INIT INFO
# Provides:          helloakka
# Required-Start:
# Required-Stop:
# Should-Start:
# Default-Start:     2 3 4 5
# Default-Stop:
# Short-Description: helloakka
### END INIT INFO

USERNAME=who??
COMMAND_HELLOAKKA="/home/$USERNAME/helloakka/run"


case "$1" in
  start)
    echo "Starting helloakka Script.."
    sudo -u $USERNAME $COMMAND_HELLOAKKA start
    echo "Done!!"
    ;;
  stop)
    echo "Stopping helloakka Script.."
    sudo -u $USERNAME $COMMAND_HELLOAKKA stop
    echo "Done!!"
    ;;
  *)
    echo "Usage: /etc/init.d/helloakka{start|stop}"
    exit 1
    ;;
esac

exit 0

권한설정 

* sudo chmod 755 helloakka  (누구든지 실행하도록 권한)

* update-rc.d 로 부팅되면 시작하기 업데이트해줌 ( sudo update-rc.d helloakka defaults) 





우아하게 시작,종료 처리하기



1. apache daemon 의존성 추가 

libraryDependencies += "commons-daemon" % "commons-daemon" % "1.0.15"


2. daemon 구현  (우아하게 종료하기 구현) 


trait ApplicationLifecycle {
def start(): Unit
def stop(): Unit
}

abstract class AbstractApplicationDaemon extends Daemon {
def application: ApplicationLifecycle // 추상메소드
def init(daemonContext: DaemonContext) {}
def start() = application.start()
def stop() = application.stop()
def destroy() = application.stop()
}

class ApplicationDaemon() extends AbstractApplicationDaemon {
def application = new HelloAkkaApplication
}

class HelloAkkaApplication() extends ApplicationLifecycle with LazyLogging {
private[this] var started: Boolean = false
private val applicationName = "hellokernel"

val actorSystem = ActorSystem(applicationName)
val actor = actorSystem.actorOf(Props[HelloWorld])
val config = actorSystem.settings.config
val timer = config.getInt("helloWorld.timer")

def start() {
logger.info(s"Starting $applicationName Service")
if (!started) {
started = true
actorSystem.actorOf(Props(
new HelloWorldCaller(
timer millis,
actor)))
}
}

def stop() {
logger.info(s"Stopping $applicationName Service")
if (started) {
started = false
actorSystem.shutdown()
}
}
}

object maintest extends App {
val application = createApplication()
def createApplication() = new ApplicationDaemon
private[this] var cleanupAlreadyRun: Boolean = false

def cleanup(){
val previouslyRun = cleanupAlreadyRun
cleanupAlreadyRun = true
if (!previouslyRun) application.stop()
}

Runtime.getRuntime.addShutdownHook(new Thread(new Runnable {
def run() {
cleanup()
}
}))

application.start()
}

-  보통 아파치 데몬은 JSVC 를 사용하여 시작하고 종료합니다. 하지만 JSVC 를 사용하지 않고 실행 시켰을 경우는 셧다운 후크를 이용해서 종료됩니다. 

JVM은 다음과 같은 상황인 경우 셧다운 이벤트를 발생시킨다.

  • 정상적으로 종료될 때. 예) 마지막 논데몬 쓰레드가 종료되었거나 System.exit()가 호출될 때.
  • JVM이 강제적으로 종료될 때. 예) 시스템 셧다운, 사용자 로그아웃, Ctrl+C 누름



참고:

http://flurdy.com/docs/scalainit/startscala.html

Comments