New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.NET code hangs when calling Edge.Func when it executes node.dll #215

Open
thomasdunn opened this Issue Nov 19, 2014 · 9 comments

Comments

Projects
None yet
6 participants
@thomasdunn

thomasdunn commented Nov 19, 2014

In my C# code using EdgeJS to run Node.js I am experiencing inconsistent but somewhat frequent hangs when Edge.Func is called. I downloaded source and made debug build and debugged into Edge.Func and found that the hang occurs when it hits the v8Thread start on the link that calls to node.dll:

NodeStart(2, new string[] { "node", AssemblyDirectory + "\\edge\\double_edge.js" });

It hangs indefinitely. My code runs within Web API v2 in a DelegatingHandler SendAsync method. Like I said its inconsistent, sometimes it runs fine, sometimes it hangs and usually after an iisreset it goes back to normal. If I send a second request to the service while the first one is hanging, the second one hangs also but I believe its because of the lock (syncRoot) inside of Edge.Func. I've seen this happen when the code is deployed to multiple different environments.

Do you have any ideas or workarounds?

Also, I experienced something similar to #85 and worked around it by including a copy of msvcr120.dll from my dev machine inside bin\edge\x64 in the deployed code. Don't know if that helps at all.

EdgeJS is awesome, so thanks for it.

-Tom

@tjanczuk

This comment has been minimized.

Show comment
Hide comment
@tjanczuk

tjanczuk Nov 19, 2014

Owner

When you say it "hangs", do you mean the NodeStart is called and never returns or something else? If you put a breakpoint on https://github.com/tjanczuk/edge/blob/master/src/double/dotnet/EdgeJs.cs#L80, does it ever get hit?

Owner

tjanczuk commented Nov 19, 2014

When you say it "hangs", do you mean the NodeStart is called and never returns or something else? If you put a breakpoint on https://github.com/tjanczuk/edge/blob/master/src/double/dotnet/EdgeJs.cs#L80, does it ever get hit?

@thomasdunn

This comment has been minimized.

Show comment
Hide comment
@thomasdunn

thomasdunn Nov 20, 2014

Its not reproducing right now but I did not have a breakpoint set there before. I would be on the NodeStart line, hit F10 to step to next line and it would never go there... Now I see that if I have the breakpoint you mention and step to next line it doesn't go to there but instead jumps to the breakpoint I have set on https://github.com/tjanczuk/edge/blob/master/src/double/dotnet/EdgeJs.cs#L87

As soon as its failing again I will try that breakpoint and report back.

thomasdunn commented Nov 20, 2014

Its not reproducing right now but I did not have a breakpoint set there before. I would be on the NodeStart line, hit F10 to step to next line and it would never go there... Now I see that if I have the breakpoint you mention and step to next line it doesn't go to there but instead jumps to the breakpoint I have set on https://github.com/tjanczuk/edge/blob/master/src/double/dotnet/EdgeJs.cs#L87

As soon as its failing again I will try that breakpoint and report back.

@tjanczuk

This comment has been minimized.

Show comment
Hide comment
@tjanczuk

tjanczuk Nov 20, 2014

Owner

That seems to indicate another CLR thread is calling the waitHandle.set(). Can you set the breakpoint on both NodeStart() and waitHandle.Set() and see if you can ever find yourself in a situation when the one on NodeStart is hit but the on eon waitHandle.Set() is not?

Owner

tjanczuk commented Nov 20, 2014

That seems to indicate another CLR thread is calling the waitHandle.set(). Can you set the breakpoint on both NodeStart() and waitHandle.Set() and see if you can ever find yourself in a situation when the one on NodeStart is hit but the on eon waitHandle.Set() is not?

@thomasdunn

This comment has been minimized.

Show comment
Hide comment
@thomasdunn

thomasdunn Nov 20, 2014

The situation you describe (hit first breakpoint and not second) has actually now happened when things work and when they don't...

I now have breakpoints set on those two lines. When things are working as expected (I get a compiled function back from Edge.Func and I am able to use it succesfully) it consistently hits the breakpoint on the first NodeStart line and does not hit the breakpoint on the waitHandle.Set line.

Again I was having trouble getting the issue to repro so I thought maybe I could force the v8Thread start code to run again by killing the node thread on w3wp via process explorer. I saw the ThreadAbortException in the debugger. Then when I made the request again the breakpoint was hit on NodeStart line. I continue and the next breakpoint was not hit, nor were others in my code. I checked back with process explorer and no new node thread showed up. The request hangs (does not complete web api request pipeline). That's the closest I've gotten to the repro (same behavior but didn't happen naturally like before).

Not sure if that helps?

I'll also report back next time it reproduces naturally and I can debug.

Thanks Tomasz.

thomasdunn commented Nov 20, 2014

The situation you describe (hit first breakpoint and not second) has actually now happened when things work and when they don't...

I now have breakpoints set on those two lines. When things are working as expected (I get a compiled function back from Edge.Func and I am able to use it succesfully) it consistently hits the breakpoint on the first NodeStart line and does not hit the breakpoint on the waitHandle.Set line.

Again I was having trouble getting the issue to repro so I thought maybe I could force the v8Thread start code to run again by killing the node thread on w3wp via process explorer. I saw the ThreadAbortException in the debugger. Then when I made the request again the breakpoint was hit on NodeStart line. I continue and the next breakpoint was not hit, nor were others in my code. I checked back with process explorer and no new node thread showed up. The request hangs (does not complete web api request pipeline). That's the closest I've gotten to the repro (same behavior but didn't happen naturally like before).

Not sure if that helps?

I'll also report back next time it reproduces naturally and I can debug.

Thanks Tomasz.

@thomasdunn

This comment has been minimized.

Show comment
Hide comment
@thomasdunn

thomasdunn Nov 20, 2014

I was able to reproduce the issue with the debugger attached. The pattern I've seen seems to be that the problem occurs on the second request to my Web API.

First request:

  • Breakpoints are on lines 42, 79, 80, 87
  • On the first request, NodeStart breakpoint is hit, I continue
  • The next line breakpoint was not hit, instead breakpoint I have set on line 42 was hit (this is node thread doubleedge JS calling back into C# code?)
  • I hit continue, it breaks on line 87 after waitHandle.WaitOne()
  • Continue, rest of code works as intended, response is returned to web api client

Note: I've turned on debugger exception setting to catch thrown CLR exceptions (in addition to unhandled)

Second request:

  • Second request is issued
  • ThreadAbortException was thrown, debugger breaks on line 79 (I was not messing around with threads in procexp.exe at all this time around):
    A first chance exception of type 'System.Threading.ThreadAbortException' occurred in EdgeJs.dll
    {Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack.}
  • After continuing, the NodeStart breakpoint is hit again
  • I hit continue, it never gets to breakpoint on next line or other breakpoints
  • It never returns, client never receives its response

I hope this helps.

thomasdunn commented Nov 20, 2014

I was able to reproduce the issue with the debugger attached. The pattern I've seen seems to be that the problem occurs on the second request to my Web API.

First request:

  • Breakpoints are on lines 42, 79, 80, 87
  • On the first request, NodeStart breakpoint is hit, I continue
  • The next line breakpoint was not hit, instead breakpoint I have set on line 42 was hit (this is node thread doubleedge JS calling back into C# code?)
  • I hit continue, it breaks on line 87 after waitHandle.WaitOne()
  • Continue, rest of code works as intended, response is returned to web api client

Note: I've turned on debugger exception setting to catch thrown CLR exceptions (in addition to unhandled)

Second request:

  • Second request is issued
  • ThreadAbortException was thrown, debugger breaks on line 79 (I was not messing around with threads in procexp.exe at all this time around):
    A first chance exception of type 'System.Threading.ThreadAbortException' occurred in EdgeJs.dll
    {Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack.}
  • After continuing, the NodeStart breakpoint is hit again
  • I hit continue, it never gets to breakpoint on next line or other breakpoints
  • It never returns, client never receives its response

I hope this helps.

@andriybuday

This comment has been minimized.

Show comment
Hide comment
@andriybuday

andriybuday Jan 21, 2015

Hi. Not sure if this is exactly the same issue, but in our case Edge.Func was hanging because of node.dll and double_edge.js files being locked by IIS. At the moment we have iisreset /stop before building the project. Also wrapper around Edge.js is a singleton.

andriybuday commented Jan 21, 2015

Hi. Not sure if this is exactly the same issue, but in our case Edge.Func was hanging because of node.dll and double_edge.js files being locked by IIS. At the moment we have iisreset /stop before building the project. Also wrapper around Edge.js is a singleton.

@DrSammyD

This comment has been minimized.

Show comment
Hide comment
@DrSammyD

DrSammyD Sep 3, 2015

I'm running into this as well

            Environment.SetEnvironmentVariable("EDGE_NODE_PARAMS", "--debug-brk");
            Task<Object> call;
            var func = Edge.Func(@"
                debugger;
                return function(data, callback){
                    callback(process.cwd());
                }
            ");
            (call = func("")).Wait();
            return (call.Result as IEnumerable<string>);

I'm not able to attach node-inspector and the Wait is never returned from. I'm running IIS locally on my machine, and this is inside of a fairly complicated web project. I could see from process explorer that w3wp.exe (IIS) did indeed have hold of the node.dll in the bin folder, but it never ran the code. Also is there a way to include node in the bin folder for non-dev machines?

DrSammyD commented Sep 3, 2015

I'm running into this as well

            Environment.SetEnvironmentVariable("EDGE_NODE_PARAMS", "--debug-brk");
            Task<Object> call;
            var func = Edge.Func(@"
                debugger;
                return function(data, callback){
                    callback(process.cwd());
                }
            ");
            (call = func("")).Wait();
            return (call.Result as IEnumerable<string>);

I'm not able to attach node-inspector and the Wait is never returned from. I'm running IIS locally on my machine, and this is inside of a fairly complicated web project. I could see from process explorer that w3wp.exe (IIS) did indeed have hold of the node.dll in the bin folder, but it never ran the code. Also is there a way to include node in the bin folder for non-dev machines?

@kxag

This comment has been minimized.

Show comment
Hide comment
@kxag

kxag Nov 20, 2015

I have a similar problem when I run unit tests using edge.js.
If i call once the edge.func no problems. If I add a second or third call then a TheardAbortException is thrown from NodeStart and UnitTest runner waits forever!

kxag commented Nov 20, 2015

I have a similar problem when I run unit tests using edge.js.
If i call once the edge.func no problems. If I add a second or third call then a TheardAbortException is thrown from NodeStart and UnitTest runner waits forever!

@tmsns

This comment has been minimized.

Show comment
Hide comment
@tmsns

tmsns Apr 7, 2016

I've encountered the same kind of ThreadAbortException issue when running unit tests on code that uses Edge.js. I have a number of different behaviours though.

  1. when devenv.exe is running the tests, the subprocess vstest.executionengine.exe seems to run correctly and doesn't send a ThreadAbortException.
  2. however when vstest.console.exe (on the build server) is running the tests, subprocess vstest.executionengine.exe is reporting the ThreadAbortException.

I've managed to solve the ThreadAbortException (I think) by gracefully ending the V8 thread (I clear the interval set in double_edge.js). Unfortunately now, both in cases 1 and 2, I've got the processes waiting and never ending (without throwing exceptions).

Still investigating.. :-)

tmsns commented Apr 7, 2016

I've encountered the same kind of ThreadAbortException issue when running unit tests on code that uses Edge.js. I have a number of different behaviours though.

  1. when devenv.exe is running the tests, the subprocess vstest.executionengine.exe seems to run correctly and doesn't send a ThreadAbortException.
  2. however when vstest.console.exe (on the build server) is running the tests, subprocess vstest.executionengine.exe is reporting the ThreadAbortException.

I've managed to solve the ThreadAbortException (I think) by gracefully ending the V8 thread (I clear the interval set in double_edge.js). Unfortunately now, both in cases 1 and 2, I've got the processes waiting and never ending (without throwing exceptions).

Still investigating.. :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment