-
Notifications
You must be signed in to change notification settings - Fork 37
Description
Feature description
Currently the Views rendering (ReactViewsRenderer::render) cannot be async, if happens that it's, it fails with io.netty.util.IllegalReferenceCountException: refCnt: 0.
In my case I'm using micronaut-views-react and my Jasascript waits for a Java Mono.
Despite the docs says that's not supported, I was able to workaround that by implementing my own ViewFilter where I create a Publisher from the Writable returned by ReactViewsRenderer::render, basically the idea is to wait until Writer::write gets called.
So I wonder whether something like this can be implemented to support async "rendering".
I copied the ViewsFilter (removing some logic I didn't need in my case), and "delay" the response until the Writer::write gets called.
It's only waiting for the first call to write, but leaving subscriber.onComplete(); only in flush and close should support multiple calls. As micronaut-views-react does not call neither flush nor close I had to call subscriber.onComplete(); in write too.
public final Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request,
ServerFilterChain chain) {
return Flux.from(chain.proceed(request))
.switchMap(response -> {
Object body = response.body();
String view = viewsResolver.resolveView(request, response).orElse(null);
if (view == null || !view.equals("App")) { // Only use this for my App View
return Flux.just(response);
}
MediaType type = UTF8_HTML;
Optional<ViewsRenderer> optionalViewsRenderer = viewsRendererLocator.resolveViewsRenderer(view, type.getName(), body);
if(optionalViewsRenderer.isEmpty()) {
return Flux.just(response);
}
ModelAndView<?> modelAndView = new ModelAndView<>(view, ((ModelAndView<?>) body).getModel().orElse(null));
viewsModelDecorator.decorate(request, modelAndView);
Writable writable = optionalViewsRenderer.get().render(view, modelAndView.getModel().orElse(null), request);
return Flux.from((Publisher<String>) subscriber -> {
subscriber.onSubscribe(new Subscription() {
@Override
public void request(long n)
{
try
{
writable.writeTo(new Writer() {
@Override
public void write(char[] buffer, int off, int len) throws IOException
{
subscriber.onNext(String.valueOf(buffer));
subscriber.onComplete();
}
@Override
public void flush() throws IOException
{
subscriber.onComplete();
}
@Override
public void close() throws IOException
{
subscriber.onComplete();
}
});
}
catch (Exception e)
{
subscriber.onError(e);
}
}
@Override
public void cancel()
{
subscriber.onComplete();
}
});
}).map(b -> response.body(b).contentType(type));
});
}
I created this repo where the problem and the workaround can be tested
Metadata
Metadata
Assignees
Type
Projects
Status