I am writing a piece of javascript (ecmascript) within a 3rd-party application which uses embedded Rhino. The application may start multiple Java threads to handle data concurrently. It seems that every Java thread starts its own embedded Rhino context which in turn runs my script.
The purpose of my script is, to receive data from the application and use it to maintain the contents of a particular file. I need a fail-safe solution to handle the concurrency from my script.
So far, what I have come up with is to call out to java and use java.nio.channels.FileLock. However, the documentation here states:
File locks are held on behalf of the entire Java virtual machine. They are not suitable for controlling access to a file by multiple threads within the same virtual machine.
Sure enough, the blocking call FileChannel.lock() does not block but throws an exception, leading to the following ugly code:
var count = 0;
while ( count < 100 )
{
try
{
var rFile = new java.io.RandomAccessFile(this.mapFile, "rw");
var lock = rFile.getChannel().lock();
try
{
// Here I do whatever the script needs to do with the file
}
finally
{
lock.release();
}
rFile.close();
break;
} catch (ex) {
// This is reached whenever another instance has a lock
count++;
java.lang.Thread.sleep( 10 );
}
}
Q: How can I solve this in a safe and reliable manner?
I have seen posts regarding Rhino sync() being similar to Java synchronized but that does not seem to work between multiple instances of Rhino.
UPDATE
I have tried the suggestion of using Synchronizer with org.mozilla.javascript.tools.shell.Global as a template:
function synchronize( fn, obj )
{
return new Packages.org.mozilla.javascript.Synchronizer(fn).call(obj);
}
Next, I use this function as follows:
var mapFile = new java.io.File(mapFilePath);
// MapWriter is a js object
var writer = new MapWriter( mapFile, tempMap );
var on = Packages.java.lang.Class.forName("java.lang.Object");
// Call the writer's update function synchronized
synchronize( function() { writer.update() } , on );
However I see that two threads enter the update() function simultaneously. What is wrong with my code?
Depending how Rhino is embedded, there are two possibilities:
If the code is executed in the Rhino shell, use the sync(f,lock) function to turn a function into a function that synchronizes on the second argument, or on the this object of its invocation if the second argument is absent. (Earlier versions only had the one-argument method, so unless your third-party application uses a recent version, you may need to use that or roll your own; see below.)
If the application is not using the Rhino shell, but using a custom embedding that does not include concurrency tools, you'll need to roll your own version. The source code for sync is a good starting point (see the source code for Global and Synchronizer; you should be able to use Synchronizer pretty much out-of-the-box the same way Global uses it).
It is possible that the problem is that the object on which you are trying to synchronize is not shared across contexts, but is created multiple times by the embedding or something. If so, you may need to use some sort of hack, especially if you have no control over the embedding. If you have no control over the embedding, you could use some kind of VM-global object on which to synchronize, like Runtime.getRuntime() or something (I can't think of any that I immediately know are single objects, but I suspect several of those with singleton APIs like Runtime are.)
Another candidate for something on which to synchronize would be something like Packages.java.lang.Class.forName("java.lang.Object"), which should refer to the same object (the Object class) in all contexts unless the embedding's class loader setup is extremely unusual.
Related
I have several functions that I'd like to replicate across different use cases in various requests and folders within the same collection (I'm using it as a template mostly, so it'll be pulling in variables externally)
There are many different suggestions in the Postman documentation but what's the best way to re-use code for such a use case?
What I've been doing lately is adding functions to my collection level pre-request script like so
collectionUtils = {
clearEnvData: function (pm) {
some useful code
},
// called after every request to ensure server coverage durring smoke testing.
cycleCurrentServer: function (serverCount, pm) {
some useful code
}
}
Then wherever I want to use these methods I do something like this
collectionUtils.cycleCurrentServer(index, pm);
I think generally the best way is to externalize the code into a library. You'll then make changes to the library and those changes will be reflected everywhere. Now there are several ways to implement this method, I'll leave with with the two that make sense for your use case:
Load your library from a remote site
If you are using some sort of development workflow that publishes your changes upstream, and you have your library published somewhere, you can load it at runtime:
pm.sendRequest("https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.11.0/dayjs.min.js", (err, res) => {
//convert the response to text and save it as an environment variable
pm.collectionVariables.set("dayjs_library", res.text());
// eval will evaluate the JavaScript code and initialize the min.js
eval(pm.collectionVariables.get("dayjs_library"));
// you can call methods in the cdn file using this keyword
let today = new Date();
console.log("today=", today);
console.log(this.dayjs(today).format())
})
Store your code on a collection variable and load it that way
A less pretty way to do it but more convenient to a lot of folks is just to drop the whole library into a collection variable like this:
Then you can load it when you need it:
const dayjs_code = pm.collectionVariables.get('dayjs_code');
// Invoke an anonymous function to get access to the dayjs library methods
(new Function(dayjs_code))();
let today = new Date();
console.log(dayjs(today).format())
In both cases when you update your library you either have to republish it or copy paste again to the collection variable. However that surely beats copy pasting a piece of code to 20 odd places and figuring out what's updated, what's not and fighting bugs while at it.
I would like to save a "snapshot" of a webpage which however should remain in an "interactive" state -> all Javascript state has to be saved and restored.
Example showing the issue I'm trying to solve: Given a webpage which executes the following script in the global scope:
function f(x) { return function() { return x; } }
var g = f(2);
I'd like to save both the function f (more or less trivial) and the variable g (which closes over x from the f invocation) to a file and restore the state of the website later.
As far as I could figure out it seems to be impossible to do this using only "web" technologies (ie. with the permissions the webpage itself has). I'm therefore guessing I'll have to implement a browser addon to achieve this.
Does something like this already exist? What would be a good starting point? I noticed that Firefox Session Restore does something similar, do you know if I could reuse this mechanism? If not would it be feasible to implement something like this as a "debugger" style addon? Are there simpler solutions?
Javascript objects hold onto DOM/other native objects. Native objects have hidden state and can be entangled with global browser state or addons.
So the only real way I can think of is to run a browser in a VM and snapshot/clone that VM.
If I write a plugin which requires a very large initialization (14 mb JavaScript which takes 1 minute to set itself up), how can I make this object persistent (for lack of a better word) across the JavaScript files used in a Meteor projects?
After the initialization of the plugin, I have an object LargeObject and when I add a file simple_todo.js, I want to use LargeObject without it taking a minute to load after EVERY change.
I cannot find any solution.
I tried making a separate package to store this in Package object, but that is cleared after every change and reinitialized.
What would be the proper way of doing that? I imagine there should be something internal in Meteor which survives hot code push.
Here are two possible solutions I:
Cache some of its properties inside Session
Cache some of its properties inside a simple collection
Use a stub in your local environment.
Session can only be used client side. You can use a collection anywhere.
Session
client
example = function () {
if(!(this.aLotOfData = Session.get('aLotOfData'))) {
this.aLotOfData = computeALotOfData()
Session.set('aLotOfData', this.aLotOfData)
}
}
Here, no data has to be transferred between client and server. For every new client that connects, the code is rerun.
Collection
lib
MuchDataCollection = new Mongo.Collection('MuchDataCollection')
server
Meteor.publish('MuchData', function (query) {
return MuchDataCollection.find(query)
})
server
example = function () {
if(
!this.aLotOfData = MuchDataCollection.findOne({
name: 'aLotOfData'
}).data
) {
this.aLotOfData = computeALotOfData()
MuchDataCollection.insert({
name: 'aLotOfData',
data: this.aLotOfData
})
}
}
Even dough you can access the collection anywhere, you don't want anyone to be able to make changes to it. Because all clients share the same collection. Collections are cached client side. Read this for more info.
Stub
A stub is probably the easiest to implement. But it's the worst solution. You'll probably have to use a settings variable and still end up having the code for the stub inside the production environment.
What to choose
It depends on your exact use-case. If the contents of the object depend on the client or user, it's probably best to use a session-var. If it doesn't go for a collection. You'll probably need to build some cache-invalidation mechanisms, but I'd say, it's worth it.
[I'm a total newbie to Javascript so take it slow.]
I'm working on an app in node.js which will have a list of plugins. Each "plugin" should be a function (or 2) that can take a string and do something with it. The app should call each plugin in turn and pass it the string. Depending on the result it might call another function in that plugin etc...
What's the best way to design this in Javascript? I don't mind having to modify the app to add every plugin as its developed but would rather avoid having to do this a lot.
Right now I'm just thinking created a module for every module then "require" it within the primary app and call the function but that seems cludgy for a few reasons (a) I need to change the parent app quiet a bit for every new plugin, (b) there's no interface I can enforce on the plugins. I was kind of hoping there was some sort of contract I could force the plugins to respect.
You can list the plugin directory, and require each file. If each file adds a function to an existing object (say, myapp.plugins), you can just forEach the object and invoke each function. You can't really enforce a contract in the code without doing weird things like invoking an AST parser; you're better off doing unit testing on plugins to make sure they work in isolation.
EDIT:
Can you elaborate a bit on this part: "If each file adds a function to an existing object (say, myapp.plugins), you can just forEach the object and invoke each function."?
var invokePlugins = function() {
var args = arguments.slice(0);
myapp.plugins.forEach(function(plugin) {
plugin.apply(plugin, args);
});
}
invokePlugins("this", "gets", "passed to", "each plugin");
Your architecture is unclear, so this is just a very rough idea of what you could do.
I'm porting an existing program to nodejs. In this program, I open a file descriptor and then hand it off to a thread which calls poll on it in order to determine when it's readable.
Instead of writing a custom C++ module, I'd really like to do this in pure javascript making use of Node's handy dandy Duplex stream.
For example I'd like to do something like this:
var device = new PollDuplexStream(fileDescriptor);
device.on('data', function(data) {
// data handling logic here
});
...
var chunk = new Buffer(...);
device.write(chunk);
It seems like this should exist, but I'm not seeing where it does. Perhaps I'm just blind? What's the real world equivalent of PollDuplexStream from the example above?
Please note that I'm explicitly looking for a solution which starts with a file descriptor rather than a path, otherwise I'd just create my own from fs.createReadStream and fs.createWriteStream.
Also I don't care that it calls poll internally - in fact, I'd prefer that it use libuv's uv_poll_* internally.
You'll need to create a binary addon which uses a uv_poll_t handle, which is able to poll for readability / writability for arbitrary file descriptors.