Question: Fibers in separate V8 context
Closed this issue · 3 comments
I'm using a separate V8 context to initialize functions:
MOCK CODE:
vm.runInContext(`return () => {}`);
In that initialized function I'm trying to use Fiber.yield(). But it complains that no fiber is running.
The code that is running the initialized function is definitely running in a fiber. something about the separate context though is throwing.
Thoughts?
I don't think you've done a good job of explaining your problem. Could you please post a full example.
I'm using separate v8 contexts to isolate code. So one parent program initializes functions in separate v8 contexts using node.js builtin vm module. In the parent context and the separate context I'm using Fibers. Example code:
index.js
const Sync = require('syncho')
Sync(() => { //This creates a fiber and runs the function in it (Fiber.run(fn))
let funcFromSeparateContext = vm.runInContext(`( function(){
const Sync = require('syncho');//<-- Somehow this module which uses require('fibers') is referencing the outside Fibers module when run on the Mac, but not in the debian environment
( (cb) => setTimeout(cb, 5000) ).sync();
})`);
let result = funcFromSeparateContext(); //Throws here with .yield() called outside fiber.
});
I've narrowed down the issue to be something different between Mac OSX and my debian based container.
When I run the code on Mac the Fiber seems to exist even in the separate v8 context and no throw happens. In the debian based container the code will throw saying .yield() was called without a Fiber running.
The last piece of the puzzle is that the fibers module lives in two different places in this scenario.
For the outer require('syncho') call the fibers module lives in:
/app/node_modules/syncho/node_modules/fibers
For the inner call it is being pulled from
/tmp/(random dir)/node_modules/syncho/node_modules/fibers
Again, on the Mac this works fine. In the container I run in to a problem.
If I modify the code to be:
const Sync = require('syncho')
Sync(() => { //This creates a fiber and runs the function in it (Fiber.run(fn))
let funcFromSeparateContext = vm.runInContext(`( function(require){
const Sync = require('syncho');
( (cb) => setTimeout(cb, 5000) ).sync();
})`);
let result = funcFromSeparateContext(require);
});
Everything works fine. In the second example, require is being passed from the outer context which will pass a cached copy of both Sync and Fibers when the require is used in the inner context. This seems to resolve the issue.
Definitely something different between mac and other environment though.
This is on Node 8.9.4 using latest syncho built with Fibers 2.0.2
A couple of other notes:
The inner context uses a different global context (including global.process). I see that you cache fiberLib on global.process (but that will not be there in the inner context). Although this shouldn't have anything to do with the problem of inconsistency I'm experiencing across the different platforms I thought I would mention it anyway.
My assumption is that somehow the binary itself is returning a reference to a instance it is creating in the Node memory space when using the Mac and somehow this doesn't happen when using the Debian binary. Not sure why that would be though. I could be missing something somewhere else though.
Any thoughts on a fix in Fibers so that it runs consistently across mac and other platforms?
Instead of require'ing the module twice just require it once and add the module to the context sandbox:
'use strict';
let Fiber = require('fibers');
let vm = require('vm');
let foo = Fiber(function() {
let sandbox = { Fiber };
vm.createContext(sandbox);
vm.runInContext('Fiber.yield()', sandbox);
console.log(3);
});
console.log(1);
foo.run();
console.log(2);
foo.run();
console.log(4);