malaporte / nashorn-commonjs-modules

CommonJS modules support for Nashorn
MIT License
108 stars 31 forks source link

How Best to Use in Servlet Environment? #12

Open mfreeman-xtivia opened 7 years ago

mfreeman-xtivia commented 7 years ago

This is really a question--what is the best/right way to use this Require module in a multi-threaded servlet environment??

So believing based on what I've read that the Nashorn engine itself is threadsafe, I create a single one of those in my servlet init().

Then on each request/thread i create new bindings, map in Java objects to be exposed to the script(s), and then do engine.eval(mainscript,newbindings).

The challenge/question is where in that sequence do I put the Require.enable(engine)? once at init? It doesn't seem like Require class exposes a flavor of enable where i could pass in the bindings (global) i want it to use?

malaporte commented 7 years ago

Hmm that's a fair point. It probably makes sense to expose an overload of enable that takes a Binding instead of the engine itself.

If you look at the code it's mostly using the engine to retrieve the global bindings (I'm not sure the other stuff is really OK in fact). Quite a bit of confusion around Bindings with Nashorn, what with the magical "global per engine" stuff, etc.

I'm pretty busy as of now, but let's leave this bug open and I'll have a look when I get some time. Or I'll gladly accept a PR if you beat me to it :)

mfreeman-xtivia commented 7 years ago

Martin, I was going to :-) but I got a little uncomfortable trying to unwind the Module class to figure out exactly where i would swap Engine over to Bindings. Maybe I will take another pass at it --

--for now I am simply firing up a complete engine/bindings/eval sequence per thread, which seems heavyweight and gross--in the end and as you suggest I would rather have just a single Engine and then be able to spin up a unique Bindings/eval per thread.

malaporte commented 7 years ago

Ah indeed I kinda missed that the engine was being passed to Module. Slightly more complex, but probably OK in the end.

One thing to know keep in mind though: even if you are re-using the same engine across all threads, you'll still need to start with new bindings for each request, meaning that each JS file you require will need to be parsed & executed each time. That's still pretty intense...

In our case, we maintain a pool of engines & bindings, accepting the fact that globals might be re-used across several requests, which is not problematic in the context where we're using it.

mfreeman-xtivia commented 7 years ago

Yeah, i oversimplified when i said one per thread--for now I am running in a Tomcat environment and I spin up a new Engine and parse everything into it the first time I see a JS request on that thread then save it away based on thread ID--so a poor's mans thread pool for the moment with the penalty that the first request on thread X pays the startup price and then everything is read from a cache based on thread ID after that

ghost commented 7 years ago

Sooo......any code changes per this issue? or just closing to close?

malaporte commented 7 years ago

Well I kinda stuck on the question at the start, and forgot that I said I might at some point look at using Bindings instead of an Engine. I'll re-open then.

kevbob1 commented 7 years ago

In my use case, I have noticed a speed up by creating a singleton NashornScriptEngine and using separate SimpleBindings per thread/request. Enabling require() on my own bindings instead of ENGINE_SCOPE would be a great feature.

I may have some time soon to implement this.

malaporte commented 7 years ago

I added an overload to Require (see #19). I think it's all that's needed, but I might be wrong - it's been a long day. I'll revisit this tomorrow but if anybody wants to test and report results feel free.

kevbob1 commented 7 years ago

This half works for me, the bindings that require is enabled on also needs to be used to eval the modules. My use case might be super special and might be violating encapsulation / abstraction for node style modules. I'll see if i can solve my problem w/ extending Module or registering a "binding provider" to Module or some such.