serverside execution

Nov 10, 2013 at 5:49 PM
Hi,

I try to find the best approach for server side usage of ClearScript. Assuming that I have a WCF service that runs stateless. The service is doing some kind of database stuff and before the data is saved, a script should run to handle some customization. I would expect that each instance of the service should have its own instance of V8ScriptEngine running a script that is loaded from disk by the static constructor of the service. The lifetime of the script file is enough because it doesn't change while the service is running. I guess the holding of V8Runtime as a static member and using the CreateScriptEngine method might be faster but also a problem with synchronization. Isn't?

Would you recommend this scenario or would you prefer another way of using ClearScript serverside.

Best regards,
Torsten
Coordinator
Nov 11, 2013 at 2:27 AM
Hi Torsten!

Is a new instance of your WCF service created for each request? Also, how does your service scale? Does a server process multiple requests simultaneously? Does it use a thread pool? We'd like to know more about your scenario.

Thanks!
Nov 11, 2013 at 12:33 PM
Edited Nov 11, 2013 at 12:35 PM
Hi,

I imagine the following scenario. There is a NT service, hosting a WCF service. Each call creates its own instance of the instance. The data might be a person with properties FirstName, LastName and Login. The FirstName and the LastName are given by the service client, the Login shall be calculated by a script. Within my draft I use Entity Framework to update the person entity during saving the entity. The following code is a part of the partial class of the model (I hope, my english is good enough to explain what I mean.)
public override int SaveChanges()
{
  // _script is a string with the JavaScript
  if (_script != null)
  {
    var addeditems = this.ChangeTracker.Entries<Person>().Where(x => x.State == EntityState.Added);

    if (addeditems.Any())
    {
      using (var engine = new V8ScriptEngine())
      {
        engine.Execute(_script);
        var compiledscript = engine.Script;

        foreach (var p in addeditems)
          compiledscript.updatelogin(p.Entity);
      }
    }
  }

  return base.SaveChanges();
}
The script might look like this:
function updatelogin(person) {

    var suffix;

    if (person.FirstName.length >= 2)
        suffix = person.FirstName.substr(0, 2);
    else {
        suffix = person.FirstName.substr(0, 1);
    }
    
    person.Login = (person.LastName + suffix).toLowerCase();
}
The user might influence how the login looks like and it works fine but I'm not sure where the best place and what way is to do so.

Torsten
Coordinator
Nov 11, 2013 at 8:06 PM
Hi Torsten,

The code above is simple and takes maximum advantage of concurrency by using a dedicated V8 runtime for each request. However, creating the runtime and context - not to mention re-executing your startup script - is relatively expensive.

To improve on that you could use a pool of preconfigured script engines, optimally equal in size to that of your thread pool (roughly equal to your CPU core count, typically). Unfortunately managing such a thing would complicate your code and trade off some of its scalability. Another factor is that your existing code guarantees a pristine script execution environment for each request, whereas a system that reused script engines would be vulnerable to rogue scripts.

A hybrid approach - pooled V8 runtimes and per-request V8 contexts - is probably the best all-around design for performance and robustness. You'd still create a new context for each request, but you'd reuse the runtime, and you could compile your startup script only once per runtime. This of course is even more complicated and brings with it a reduced performance gain.

So if you're happy with the performance of your system as is, there's no reason to change it :)

Good luck!