Vert.x verticle 여러 개 배포하기

🗓 ⏰ 소요시간 19 분

회사에서 Vertx. 라는 프레임워크를 다루게 되었습니다. 처음 접할 때 이해하는게 쉽지 않았는데, 알면 알수록 상당히 유용한 프레임워크입니다. Vert.x 에 대해서는 조만간 개념 정리해서 따로 올리도록 하겠습니다.

https://vertx.io/

오늘 포스팅에서는 Verticle 을 여러 개 배포하는 법을 살펴보겠습니다.

Vert.x 프로젝트를 shadowJar 를 이용해 jar 파일로 떨군 후 리눅스에서 실행시키는 건 간단해서 별 문제가 안됐습니다. 문제는 shadowJar config 에서 MainVerticle 를 하나만 지정할 수 있기 때문에 verticle 을 여러 개 사용하려면 다른 방법이 필요했습니다.

Main Verticle 만들기

App.java 라는 메인 버티클을 먼저 만들고 MainVerticle 로 지정해주겠습니다.

1
2
3
4
5
6
7
8
9
10
shadowJar {
mainClassName = 'io.vertx.core.Launcher'
classifier = 'fat'
manifest {
attributes 'Main-Verticle': 'com.future.creator.App'
}
mergeServiceFiles {
include 'META-INF/services/io.vertx.core.spi.VerticleFactory'
}
}

Verticle 하나를 배포하기

물론 MainVerticle 을 지정해주면 별 거 없이 돌아가겠지만 deployVerticle 메소드를 이용해 수동으로 배포하는 법을 살펴보겠습니다.

실제 로직이 들어간 verticle 을 TestVerticle 이라고 할 때 다음과 같이 App.java 를 작성할 수 있습니다.

1
2
3
4
Verticle myVerticle = new MyVerticle();
vertx.deployVerticle(myVerticle);

vertx.deployVerticle("com.future.creator.TestVerticle");

verticle 배포는 async 로 처리되기 때문에 callback 을 넘겨줘서 배포가 완료될 시점에 처리할 작업을 정의할 수 있습니다.

1
2
3
4
5
6
7
vertx.deployVerticle("com.future.creator.TestVerticle", res -> {
if (res.succeeded()) {
System.out.println("Deployment id is: " + res.result());
} else {
System.out.println("Deployment failed!");
}
});

Verticle 여러 개 배포하기

이런 식으로 MainVerticle 을 하나 만들어놓고 배포할 verticle 들을 전부 배포해주시면 되는데요,
여러 verticle 을 배포할 경우엔 각각 async 방식으로 돌기 때문에 전체적인 결과를 한번에 확인하기가 어렵습니다.
이럴 땐 Vert.x API 중 CompositeFuture 를 이용하면 비동기 결과를 묶어서 확인 후 처리할 수 있습니다.

  • CompositeFuture.all 전부 성공하거나 하나라도 실패할 경우 리턴
  • CompositeFuture.any 하나가 성공하거나 전부 다 실패할 경우 리턴
  • CompositeFuture.join 전부 성공하거나 전부 완료되었지만 하나라도 실패할 경우 리턴

이를 이용해서 코드를 작성하면 다음과 같습니다. 저는 모두 성공하면 성공, 하나라도 실패하면 실패하는 all 을 이용했습니다.

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
32
33
34
35
public class App extends AbstractVerticle {

private static final Logger LOGGER = LoggerFactory.getLogger(App.class);

@Override
public void start(Future<Void> startFuture) throws Exception {

LOGGER.info("START DEPLOYMENT");
LOGGER.info("Using {} Event Loops.", 2 * Runtime.getRuntime().availableProcessors());

Future<String> future1 = Future.future();
Future<String> future2 = Future.future();
Future<String> future3 = Future.future();

vertx.deployVerticle("com.future.creator.TestVerticle1", future1.completer());
vertx.deployVerticle("com.future.creator.TestVerticle2", future2.completer());
vertx.deployVerticle("com.future.creator.TestVerticle3", future3.completer());

CompositeFuture.all(future1, future2, future3).setHandler(ar -> {

if (ar.succeeded()) {

LOGGER.info("All Verticles deployed.");

} else {
String cause = ar.cause() == null ? "" : ar.cause().getMessage();

LOGGER.info("Verticle deployment failed : {}", cause);

if (!startFuture.failed())
startFuture.fail(cause);
}
});
}
}

배포 결과 확인

Linux command 를 실행하는 TestVerticle 을 3개 만들어서 한번에 실행시켜 봤습니다.

모두 성공하는 경우

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-- 배포 시작
01:31:56.461 [vert.x-eventloop-thread-0] INFO com.future.creator.App - START DEPLOYMENT
01:31:56.468 [vert.x-eventloop-thread-0] INFO com.future.creator.App - Using 2 Event Loops.

-- 0, 1 Thread 2개에서 각각 작업 시작함
01:31:56.516 [vert.x-eventloop-thread-1] DEBUG o.z.exec.ProcessExecutor - Executing [java, -version].
01:31:56.523 [vert.x-eventloop-thread-0] DEBUG o.z.exec.ProcessExecutor - Executing [java, -version].
01:31:56.554 [vert.x-eventloop-thread-1] DEBUG o.z.exec.ProcessExecutor - Started java.lang.UNIXProcess@19a240e
01:31:56.561 [vert.x-eventloop-thread-0] DEBUG o.z.exec.ProcessExecutor - Started java.lang.UNIXProcess@f08c85

-- 작업 종료 deploy 종료
01:31:57.149 [vert.x-eventloop-thread-0] DEBUG o.zeroturnaround.exec.WaitForProcess - java.lang.UNIXProcess@f08c85 stopped with exit code 0
01:31:57.154 [vert.x-eventloop-thread-0] INFO com.future.creator.TestVerticle2
01:31:57.168 [vert.x-eventloop-thread-1] DEBUG o.zeroturnaround.exec.WaitForProcess - java.lang.UNIXProcess@19a240e stopped with exit code 0
01:31:57.169 [vert.x-eventloop-thread-1] INFO com.future.creator.TestVerticle1

-- 나머지 하나 verticle3 deploy 중
01:31:57.169 [vert.x-eventloop-thread-1] DEBUG o.z.exec.ProcessExecutor - Executing [java, -version].
01:31:57.182 [vert.x-eventloop-thread-1] DEBUG o.z.exec.ProcessExecutor - Started java.lang.UNIXProcess@169db54
01:31:57.518 [vert.x-eventloop-thread-1] DEBUG o.zeroturnaround.exec.WaitForProcess - java.lang.UNIXProcess@169db54 stopped with exit code 0
01:31:57.519 [vert.x-eventloop-thread-1] INFO com.future.creator.TestVerticle3

-- 모두 deploy 완료
01:31:57.520 [vert.x-eventloop-thread-0] INFO com.future.creator.App - All Verticles deployed.

실패하는 경우

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
-- deploy 시작
01:29:14.074 [vert.x-eventloop-thread-0] INFO com.future.creator.App - START DEPLOYMENT
01:29:14.106 [vert.x-eventloop-thread-0] INFO com.future.creator.App - Using 2 Event Loops.

-- verticle 1에서 deploy 실패
-- 각각 deploy 중인데 이미 verticle 1이 실패하였으므로 벌써 전체 deploy 는 실패로 판정됨.
01:29:14.203 [vert.x-eventloop-thread-0] INFO com.future.creator.App - Verticle deployment failed : com.future.creator.TestVerticle1

-- 0, 1 쓰레드에서 verticle 2, 3 deploy
01:29:14.245 [vert.x-eventloop-thread-1] DEBUG o.z.exec.ProcessExecutor - Executing [java, -version].
01:29:14.247 [vert.x-eventloop-thread-0] DEBUG o.z.exec.ProcessExecutor - Executing [java, -version].
01:29:14.307 [vert.x-eventloop-thread-1] DEBUG o.z.exec.ProcessExecutor - Started java.lang.UNIXProcess@eeea38
01:29:14.344 [vert.x-eventloop-thread-0] DEBUG o.z.exec.ProcessExecutor - Started java.lang.UNIXProcess@c8642a
01:29:14.870 [vert.x-eventloop-thread-0] DEBUG o.zeroturnaround.exec.WaitForProcess - java.lang.UNIXProcess@c8642a stopped with exit code 0
01:29:14.901 [vert.x-eventloop-thread-0] INFO com.future.creator.TestVerticle3
01:29:14.937 [vert.x-eventloop-thread-1] DEBUG o.zeroturnaround.exec.WaitForProcess - java.lang.UNIXProcess@eeea38 stopped with exit code 0
01:29:14.939 [vert.x-eventloop-thread-1] INFO com.future.creator.TestVerticle2
io.vertx.core.impl.NoStackTraceThrowable: com.future.creator.TestVerticle1

-- future를 fail 처리했기 때문에 deploy 실패함.
-- 이거 없으면 error 있어도 그냥 전체 배포했다고 완료됨.
May 25, 2018 1:29:14 AM io.vertx.core.impl.launcher.commands.VertxIsolatedDeployer
SEVERE: Failed in deploying verticle

io.vertx.core.impl.NoStackTraceThrowable: com.future.creator.TestVerticle1
io.vertx.core.impl.NoStackTraceThrowable: com.future.creator.TestVerticle1