Professional Documents
Culture Documents
Infcon2022 Armeria
Infcon2022 Armeria
Infcon2022 Armeria
$ cd infcon-armeria
$ ./gradlew build
세부 내용
타이틀 삽입 시 프리텐다드 Bold 18pt
세부 내용
Things I wish we had known in advance
비동기 서버 그까이꺼, Request Scoping만 알면 끝!
Armeria로 Reactive Streams와 놀자! 1
Armeria로 Reactive Streams와 놀자! 2
Through this hands on, we are going to build…
AuthServer
(3)
Backend-1
(2) (5)
(4)
(1)
Client Frontend (6)
(8)
Backend-2
(7)
If you are new to an asynchronous server
You are going to learn the basic principle of an asynchronism.
If you are new to Armeria
You are going to learn some of Armeria APIs.
If you ve already used Armeria
Please, go out and listen to another session. 😆
Hello, Armeria!
AuthServer
Backend-1
(1)
Client Frontend
(2)
Backend-2
Hello, Armeria!
public static void main(String[] args) {
final ServerBuilder serverBuilder = Server.builder();
final Server server =
serverBuilder.http(8080)
.service("/infcon", (ctx, req) -> {
return HttpResponse.of("Hello, Armeria!");
})
.build();
server.start().join();
}
$ curl http://127.0.0.1:8080/infcon
Hello, Armeria!
public final class HelloService implements HttpService {
@Override
public HttpResponse serve(
ServiceRequestContext ctx, HttpRequest req) throws Exception {
return HttpResponse.of("Hello, Armeria!");
}
}
Backend that responds slowly
AuthServer
Backend-1
(3)
(2)
(1)
Client Frontend
(4)
Backend-2
Backend that responds slowly
private Backend(String name, int port) {
server = Server.builder()
.http(port)
.service("/foo", (ctx, req) -> {
return HttpResponse.delayed(HttpResponse.of("response from: " + name),
Duration.ofSeconds(3));
})
.build();
}
Let s do the test!
@Test
void backend() {
// response from: foo
final Backend foo = Backend.of("foo", 9000);
foo.start();
Client Frontend
Aggregating the response
An HTTP response consists of frames that are not sent at once.
Have to handle the frames one by one or just aggregate it.
@Override
public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception {
return fooClient.get("/foo");
}
}
$ curl http://127.0.0.1:8080/infcon
Composing responses
AuthServer
Backend-1
(3)
(2)
(1)
Client Frontend (4)
(6)
Backend-2
(5)
Before composing, how do we aggregate?
@Override
public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception {
return HttpResponse.from(
fooClient.get("/foo").aggregate().handle((fooResponse, cause1) -> {
return HttpResponse.of(fooResponse.contentUtf8());
}));
}
// Or
@Override
public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception {
final CompletableFuture<HttpResponse> future = new CompletableFuture<>();
fooClient.get("/foo").aggregate().thenAccept(
fooResponse -> future.complete(HttpResponse.of(HttpStatus.OK,
MediaType.PLAIN_TEXT_UTF_8,
fooResponse.contentUtf8())));
return HttpResponse.from(future);
}
Composing responses
public static void main(String[] args) {
final Backend foo = Backend.of("foo", 9000);
foo.start();
final Backend bar = Backend.of("bar", 9001);
bar.start();
@Override
public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception {
...
}
}
Decorator
AuthServer
(3)
Backend-1
(2) (5)
(4)
(1)
Client Frontend (6)
(8)
Backend-2
(7)
Decorator
A decorating service or decorator is a service
that wraps another service to intercept an
incoming request or an outgoing response.
An implementation of the decorator pattern
Core features such as logging, metrics and
distributed tracing are implemented as decorators.
https://www.slideshare.net/JulieKim1/armeriaworkshop2019-openchat-julie
AuthDecorator
@Override
public HttpResponse serve(
HttpService delegate, ServiceRequestContext ctx, HttpRequest req) throws Exception {
final CompletableFuture<HttpResponse> future = new CompletableFuture<>();
authClient.get("/auth").aggregate().whenComplete((aggregatedHttpResponse, cause) -> {
try {
future.complete(delegate.serve(ctx, req));
} catch (Throwable t) {
future.completeExceptionally(t);
}
});
return HttpResponse.from(future);
}