micronaut-views icon indicating copy to clipboard operation
micronaut-views copied to clipboard

Feature: Reactive Soy (v2)

Open sgammon opened this issue 5 years ago • 20 comments

This changeset amends the Soy view renderer, to support a new interface called ReactiveViewRenderer. The new interface generates a Flowable instead of a Writable, so that reactive chunked responses can be generated when the renderer is waiting on Future values to resolve.

Caveat: see discussion on #26 (v1 of Reactive Soy), in which @graemerocher and I discuss the ability to dynamically switch to chunked responses, which hasn't landed yet. Until that time, this PR will block forever/fail on unresolved futures in the render context. Workarounds for this might include:

  1. always sending a chunked response, for now (i.e. opting out of dynamic switching, at the cost of some client efficiency)
  2. always sending a synchronous response, for now, i.e. resolving futures before rendering (at the cost of some server efficiency)
  3. working upstream to enable dynamic decision making for chunked responses (this is more invasive, of course, but also higher impact, and probably exceeds the scope of my abilities with Micronaut)

sgammon avatar Feb 26 '20 19:02 sgammon

@graemerocher / @jameskleeh your feedback on the above would be very welcome. particularly, the ideas in the description about workarounds for the chunking issue.

i'm hoping to get this PR in even if the chunking issue isn't quite ready yet, if you are open to it (we are increasingly using micronaut in prod and this would help on a number of fronts)

all of the above respectfully, of course, and thank you again for your time

also, this PR supersedes the last one, it's based off the latest master and cleans up my previous approach in a few ways. the SoyContext feature was not in yet, that one is new to this PR.

sgammon avatar Feb 26 '20 20:02 sgammon

@sgammon Sorry for the late reply. I debugged this and it is essentially writing the view as a single chunk to the response which is not ideal. I'm not sure that is desirable?

I think we should prioritize fixing this problem as it won't work as designed. Could you raise an issue in Micronaut core to fix the handling of stream response detection?

graemerocher avatar Mar 06 '20 14:03 graemerocher

@graemerocher sure thing, i'll raise a bug on core (thank you for your response!)

update: filed as micronaut-projects/micronaut-core#2902

sgammon avatar Mar 09 '20 19:03 sgammon

Depends on #37

graemerocher avatar Apr 21 '20 12:04 graemerocher

@sgammon can you please rebase master branch and fix the conflicts, please?

ilopmar avatar Jul 08 '20 11:07 ilopmar

@ilopmar afaik we are waiting on upstream changes here still (specifically, the ability to switch the chunked serving on or off depending on chunk count)

@graemerocher can you advise?

sgammon avatar Aug 10 '20 17:08 sgammon

@sgammon the upstream changes went into Micronaut 2.0 so the PR needs rebasing on Micronaut 2.0 and it should be good to go

graemerocher avatar Aug 17 '20 06:08 graemerocher

@graemerocher understood. i'll do that this week or over the weekend, that's great news!

to use the switched chunk response, do i just return the proper response type based on what needs to happen?

sgammon avatar Aug 17 '20 18:08 sgammon

This PR looks very promising.

@sgammon @graemerocher Any updates?

laurentpellegrino avatar Dec 22 '20 21:12 laurentpellegrino

@lpellegr this needs to be cleaned up and converged with our internal forks. it's working in production and over the past few months has successfully served well over 1m requests. with precompiled templates, it's insanely fast.

if you are interested in adopting, let me know and i can move that up on my plate. we use those forks from @sgammon/elide, which is a meta-framework that wraps Micronaut.

sgammon avatar Dec 22 '20 23:12 sgammon

@sgammon Thanks for your answer. I would really love to adopt this. Precompiled templates are also something I started to look at but the current micronaut-views documentation looks quite obscure regarding this point.

laurentpellegrino avatar Dec 22 '20 23:12 laurentpellegrino

@lpellegr i hope it would be okay to start with a code sample in Bazel, that would be much easier. i haven't yet approached build tooling for precompiling soy templates in, say, Gradle or Maven, but it's theoretically the same as any other route (i.e. the Micronaut/Soy layer just expects templates to exist on the classpath - they are compiled Java classes at a computable package path based on the template namespace)

the micronaut/soy layer is in charge of converting a @View-annotated controller method into a Soy render routine. it captures the return type of the method, and provides it as Soy render context. so, in your method, you return a map of data, which is converted into Soy properties and provided to the template mentioned in your @View annotation.

as an example, in Kotlin (this would be an Elide controller, but in this case it's functionally the same as Micronaut):

some_page.soy

{namespace some.soy.path}

{template templateName}
  {@param name: string /}  // Name for the salutation.

  <b>Hello, {$name}!</b>
{/template}

SomeController.kt

@Controller
class SomeController {
    @View("some.soy.path.templateName")
    @Get("/", produces = ["text/html;charset=UTF-8"])
    fun home(request: HttpRequest<*>): Map<String, String> {
        // do something to calculate context
        return mapOf("name" to "World")
    }
}
curl http://localhost:8080/

<b>Hello, World!</b>

I do see some Soy plugins for Gradle and Maven, or, if you are using Bazel (or willing to learn it, it's awesome), you can use the compiler directly via rules_closure.

sgammon avatar Dec 28 '20 22:12 sgammon

@sgammon Thanks for your help (and happy new year!). I was able to generate compiled templates using Gradle and to use them. However, using compiled templates requires to override SoyFileSetProvider#provideCompiledTemplates with something like:

@Override
public SoySauce provideCompiledTemplates() {
    return new SoySauceBuilder().build();
}

Adding classes in the classpath is not enough. Also, as soon as the previous method is overridden, if classes for compiled templates are not found in the classpath, then rendering always fails, and live compilation is not triggered. I don't know if the current behavior is normal but, personally, I found the documentation misleading:

If compiled templates can’t be located by the SoyFileSetProvider, templates are pre-compiled into bytecode at server startup

Another thing I struggled with and required me to use a customized version of micronaut-views is Soy ij data. A dedicated issue has been opened. I would love to have your thought.

laurentpellegrino avatar Jan 02 '21 18:01 laurentpellegrino

@lpellegr ah drat, it looks like there are some crossed wires here - on our internal fork, we have a fix for the IJ data and I can also dig up a sample for how we load templates. let me get back to you on this, and happy new year back! :)

sgammon avatar Jan 04 '21 05:01 sgammon

@sgammon Any news?

laurentpellegrino avatar Jan 11 '21 21:01 laurentpellegrino

This has breaking changes. Thus, it will need to wait until the next mayor version of Micronaut Views module.

sdelamo avatar Mar 25 '21 05:03 sdelamo

@sdelamo I just noticed the first milestone of Micronaut 3.0. Any chance to get this PR sorted?

laurentpellegrino avatar May 31 '21 08:05 laurentpellegrino

@lpellegr this was only ever waiting on the ability to dynamically switch between chunked responses and unary (buffered) responses, based on encountering a Future (or descendent) during the render flow.

if there's a way to trigger that now, we can amend this code to do that and merge -- otherwise, we could simply decide to treat it as an enhancement later. IIRC, right now, it will simply block rendering and wait for the future to complete, which is sub-optimal in many circumstances

sgammon avatar Jun 03 '21 22:06 sgammon

we have been using this in production for some time now, as i know you are as well. so i think the code is very stable, it just needs a rebase, quick cleanup, and the mechanism to return chunked bytes instead of a single response.

sgammon avatar Jun 03 '21 22:06 sgammon

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

CLAassistant avatar Feb 07 '24 21:02 CLAassistant