Skip to content
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

Request making a second request makes it hang #164

Closed
jonyo opened this issue May 15, 2017 · 41 comments
Closed

Request making a second request makes it hang #164

jonyo opened this issue May 15, 2017 · 41 comments
Labels

Comments

@jonyo
Copy link
Contributor

jonyo commented May 15, 2017

For a project, we have multiple micro services, running in different containers each set up with it's own xdebug port so I can debug a specific micro service or multiple microservices at once. Everything is working well, breakpoints break, code is able to step properly etc. Unless one microservice makes a call to another one that makes a call back to the first micro service, at which point it hangs until the connection times out.

Before it times out though, in the editor it shows 2 requests on the call stack. If I put a breakpoint in the code in "container A" before the point it makes that call to container B, it breaks just fine. If I then try to step through it, it hangs once it gets to the line that makes the call to container B until the container B call times out, then it continues on with a timeout error creating a stop point in xdebug.

I was able to simplify the error down to a simple test not involving multiple containers or anything, basically just have a call make a curl connection to make a second call.

PHP version: 5.6.30
XDebug version: 2.5.0
Adapter version: 1.10.0

Your launch.json:

{
	"version": "0.2.0",
	"configurations": [
		{
			"name": "Listen for XDebug",
			"type": "php",
			"request": "launch",
			"port": 9002,
			"localSourceRoot": "${workspaceRoot}",
			"serverSourceRoot": "/var/www/public/releases/local_source"
		}
	]
}

XDebug php.ini config:

zend_extension=xdebug.so
[xdebug]
xdebug.remote_enable=1
xdebug.remote_autostart=1
xdebug.remote_connect_back=0
xdebug.remote_mode=req
xdebug.remote_port=9002
xdebug.remote_host=10.55.55.1

XDebug logfile (from setting xdebug.remote_log in php.ini):

Log opened at 2017-05-15 17:02:39
I: Connecting to configured address/port: 10.55.55.1:9002.
I: Connected to client. :-)
-> <init xmlns="urn:debugger_protocol_v1" xmlns:xdebug="http://xdebug.org/dbgp/xdebug" fileuri="file:///var/www/public/releases/local_source/app/webroot/test2.php" language="PHP" xdebug:language_version="5.6.30-1+deb.sury.org~xenial+1" protocol_version="1.0" appid="26056"><engine version="2.5.0"><![CDATA[Xdebug]]></engine><author><![CDATA[Derick Rethans]]></author><url><![CDATA[http://xdebug.org]]></url><copyright><![CDATA[Copyright (c) 2002-2016 by Derick Rethans]]></copyright></init>

<- breakpoint_list -i 1
-> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="http://xdebug.org/dbgp/xdebug" command="breakpoint_list" transaction_id="1"></response>

<- breakpoint_set -i 2 -t line -f file:///var/www/public/releases/local_source/app/webroot/test2.php -n 10
-> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="http://xdebug.org/dbgp/xdebug" command="breakpoint_set" transaction_id="2" id="260560003"></response>

<- breakpoint_list -i 3
-> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="http://xdebug.org/dbgp/xdebug" command="breakpoint_list" transaction_id="3"><breakpoint type="line" filename="file:///var/www/public/releases/local_source/app/webroot/test2.php" lineno="10" state="enabled" hit_count="0" hit_value="0" id="260560003"></breakpoint></response>

<- breakpoint_list -i 4
-> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="http://xdebug.org/dbgp/xdebug" command="breakpoint_list" transaction_id="4"><breakpoint type="line" filename="file:///var/www/public/releases/local_source/app/webroot/test2.php" lineno="10" state="enabled" hit_count="0" hit_value="0" id="260560003"></breakpoint></response>

<- breakpoint_set -i 5 -t exception -x *
-> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="http://xdebug.org/dbgp/xdebug" command="breakpoint_set" transaction_id="5" id="260560004"></response>

<- run -i 6
Log opened at 2017-05-15 17:02:39
I: Connecting to configured address/port: 10.55.55.1:9002.
I: Connected to client. :-)
-> <init xmlns="urn:debugger_protocol_v1" xmlns:xdebug="http://xdebug.org/dbgp/xdebug" fileuri="file:///var/www/public/releases/local_source/app/webroot/test2.php" language="PHP" xdebug:language_version="5.6.30-1+deb.sury.org~xenial+1" protocol_version="1.0" appid="26052"><engine version="2.5.0"><![CDATA[Xdebug]]></engine><author><![CDATA[Derick Rethans]]></author><url><![CDATA[http://xdebug.org]]></url><copyright><![CDATA[Copyright (c) 2002-2016 by Derick Rethans]]></copyright></init>

<- breakpoint_list -i 1
-> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="http://xdebug.org/dbgp/xdebug" command="breakpoint_list" transaction_id="1"></response>

<- breakpoint_set -i 2 -t line -f file:///var/www/public/releases/local_source/app/webroot/test2.php -n 10
-> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="http://xdebug.org/dbgp/xdebug" command="breakpoint_set" transaction_id="2" id="260520005"></response>

<- stop -i 3
-> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="http://xdebug.org/dbgp/xdebug" command="stop" transaction_id="3" status="stopped" reason="ok"></response>

-> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="http://xdebug.org/dbgp/xdebug" command="run" transaction_id="6" status="stopping" reason="ok"></response>

<- breakpoint_list -i 7
-> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="http://xdebug.org/dbgp/xdebug" command="breakpoint_list" transaction_id="7"><breakpoint type="line" filename="file:///var/www/public/releases/local_source/app/webroot/test2.php" lineno="10" state="enabled" hit_count="0" hit_value="0" id="260560003"></breakpoint><breakpoint type="exception" state="enabled" hit_count="0" hit_value="0" id="260560004"></breakpoint></response>

<- stop -i 8
-> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="http://xdebug.org/dbgp/xdebug" command="stop" transaction_id="8" status="stopped" reason="ok"></response>

Log closed at 2017-05-15 17:02:48

Adapter logfile (from setting "log": true in launch.json):

<- launchResponse
Response {
  seq: 0,
  type: 'response',
  request_seq: 2,
  command: 'launch',
  success: true }
new connection 1
<- threadEvent
ThreadEvent {
  seq: 0,
  type: 'event',
  event: 'thread',
  body: { reason: 'started', threadId: 1 } }
<- initializedEvent
InitializedEvent { seq: 0, type: 'event', event: 'initialized' }
-> threadsRequest
{ command: 'threads', type: 'request', seq: 3 }
<- threadsResponse
Response {
  seq: 0,
  type: 'response',
  request_seq: 3,
  command: 'threads',
  success: true,
  body: { threads: [ Thread { id: 1, name: 'Request 1 (1:02:39 PM)' } ] } }
-> setBreakpointsRequest
{ command: 'setBreakpoints',
  arguments: 
   { source: 
      { path: '/Users/jonathanfoote/zumba/git/public/app/webroot/test2.php',
        name: 'test2.php' },
     lines: [ 10 ],
     breakpoints: [ { line: 10 } ],
     sourceModified: false },
  type: 'request',
  seq: 4 }
<- setBreakpointsResponse
Response {
  seq: 0,
  type: 'response',
  request_seq: 4,
  command: 'setBreakpoints',
  success: true,
  body: { breakpoints: [ { verified: true, line: 10 } ] } }
-> setFunctionBreakpointsRequest
{ command: 'setFunctionBreakpoints',
  arguments: { breakpoints: [] },
  type: 'request',
  seq: 5 }
<- setFunctionBreakpointsResponse
Response {
  seq: 0,
  type: 'response',
  request_seq: 5,
  command: 'setFunctionBreakpoints',
  success: true,
  body: { breakpoints: [] } }
-> setExceptionBreakpointsRequest
{ command: 'setExceptionBreakpoints',
  arguments: { filters: [ '*' ] },
  type: 'request',
  seq: 6 }
<- setExceptionBreakpointsResponse
Response {
  seq: 0,
  type: 'response',
  request_seq: 6,
  command: 'setExceptionBreakpoints',
  success: true }
-> configurationDoneRequest
{ command: 'configurationDone', type: 'request', seq: 7 }
-> threadsRequest
{ command: 'threads', type: 'request', seq: 8 }

<- threadsResponse
Response {
  seq: 0,
  type: 'response',
  request_seq: 8,
  command: 'threads',
  success: true,
  body: { threads: [ Thread { id: 1, name: 'Request 1 (1:02:39 PM)' } ] } }
new connection 2
<- threadEvent
ThreadEvent {
  seq: 0,
  type: 'event',
  event: 'thread',
  body: { reason: 'started', threadId: 2 } }
<- initializedEvent
InitializedEvent { seq: 0, type: 'event', event: 'initialized' }
-> threadsRequest
{ command: 'threads', type: 'request', seq: 9 }
<- threadsResponse
Response {
  seq: 0,
  type: 'response',
  request_seq: 9,
  command: 'threads',
  success: true,
  body: 
   { threads: 
      [ Thread { id: 1, name: 'Request 1 (1:02:39 PM)' },
        Thread { id: 2, name: 'Request 2 (1:02:39 PM)' } ] } }
-> setBreakpointsRequest
{ command: 'setBreakpoints',
  arguments: 
   { source: 
      { path: '/Users/jonathanfoote/zumba/git/public/app/webroot/test2.php',
        name: 'test2.php' },
     lines: [ 10 ],
     breakpoints: [ { line: 10 } ],
     sourceModified: false },
  type: 'request',
  seq: 10 }
-> disconnectRequest
{ command: 'disconnect',
  arguments: { restart: false },
  type: 'request',
  seq: 11 }
<- configurationDoneResponse
Response {
  seq: 0,
  type: 'response',
  request_seq: 7,
  command: 'configurationDone',
  success: true }
<- outputEvent
OutputEvent {
  seq: 0,
  type: 'event',
  event: 'output',
  body: { category: 'console', output: 'connection 1 closed\n' } }
connection 1 closed
<- threadEvent
ThreadEvent {
  seq: 0,
  type: 'event',
  event: 'thread',
  body: { reason: 'exited', threadId: 1 } }
-> setFunctionBreakpointsRequest
{ command: 'setFunctionBreakpoints',
  arguments: { breakpoints: [] },
  type: 'request',
  seq: 12 }

Code snippet to reproduce:

<?php

if (empty($_GET['connect'])) {
	$ch = curl_init('http://localhost/' . $_SERVER['REQUEST_URI'] . '?connect=1');
	curl_exec($ch);
	curl_close($ch);
	die ('end of initial call');
}

phpinfo();
@SarnaMC
Copy link

SarnaMC commented Oct 24, 2017

Have the same problem

@ZurabWeb
Copy link

This is really annoying, the browser tab just hangs and time out if there are parallel requests to the same app. I really hope it's fairly simple to fix...

@SarnaMC
Copy link

SarnaMC commented Oct 24, 2017

@ZurabWeb yes, me too, but look at issue open time. 15 May. 5 months :(

@ZurabWeb
Copy link

@SarnaMC I think it didn't get the attention of the author. Maybe with more comments we could draw their attention.

@felixfbecker
Copy link
Contributor

I get a notification for every comment and more comments won't fix the issue ;)
I don't have the capacity to look into this and it might not even be a bug in the adapter. If you care about this why not look into it yourself? It's open source ⭐️

@jonyo
Copy link
Contributor Author

jonyo commented Oct 24, 2017

@felixfbecker Maybe you already noticed this but to me, it looks like on the second request, it attempts to send the breakpoints, and is hung before it gets a response. Looking at the code, if I'm reading it correctly it looks like it attempts to send the breakpoints to all connections. I wonder if it tries to send it to the initial connection which is paused so is not going to respond...

I was going to test this theory but can't seem to get the extension set up for debugging, it keeps telling me Debug adapter process has terminated unexpectedly when I try to start the debugger in the VSC extension debug window.

@felixfbecker
Copy link
Contributor

That could very well be the problem.

I have not debugged this extension in a long time, the config might have changed. What config did you use exactly? Did you follow the contribution guide?

@calebporzio
Copy link

@jonyo - I'm working on a project that uses microservices and this is a deal breaker for me too - hope you figure something out.

@jonyo
Copy link
Contributor Author

jonyo commented Oct 24, 2017

@felixfbecker

What config did you use exactly?

For debugging the extension, used the "launch extension" config:

    {
      "name": "Launch Extension",
      "type": "extensionHost",
      "request": "launch",
      "runtimeExecutable": "${execPath}",
      "args": ["--extensionDevelopmentPath=${workspaceRoot}"],
      "sourceMaps": true,
      "outDir": "${workspaceRoot}/out"
    }

Did you follow the contribution guide?

I tried to as close as possible, ran into a few issues I am not sure about:

code testproject --extensionDevelopmentPath=.

When I try this it gives some errors:

[.fseventsd]: Cannot read file .fseventsd/package.json: EACCES: permission denied, open '.fseventsd/package.json'.
Close
Error[.Spotlight-V100]: Cannot read file .Spotlight-V100/package.json: EACCES: permission denied, open '.Spotlight-V100/package.json'.
Close
Error[.PKInstallSandboxManager-SystemSoftware]: Cannot read file .PKInstallSandboxManager-SystemSoftware/package.json: EACCES: permission denied, open '.PKInstallSandboxManager-SystemSoftware/package.json'.

I was able to just open the test project using the menus but not sure if that sets it up correctly.

Here's a quick screencast:

https://screencast.com/t/8pqRSIq9iEBy

@felixfbecker
Copy link
Contributor

That sounds very weird to me. What npm/node version are you running? Did you try a git clean fresh npm install?

@jonyo
Copy link
Contributor Author

jonyo commented Oct 24, 2017

$ node --version
v8.7.0
$ npm --version
5.4.2

I tried fresh npm install and typings install as well.

I wonder if it is something to do with the outDir, I get a warning that is deprecated in favor of outFiles.

This is on macOS 10.13 High Sierra if that makes a difference.

@felixfbecker
Copy link
Contributor

You need to use the Node version that VS Code uses, which is v7.
A good reference is always the CI config:
https://github.com/felixfbecker/vscode-php-debug/blob/ed5a99d0d4a5e6840186c21890b7027901609b2e/.travis.yml#L14

@jonyo
Copy link
Contributor Author

jonyo commented Oct 24, 2017

@felixfbecker
Did that, same result... Then I looked at the rest of the travis config and noticed this line...

https://github.com/felixfbecker/vscode-php-debug/blob/ed5a99d0d4a5e6840186c21890b7027901609b2e/.travis.yml#L22

Ran that, now it's working. 👍 Will report back if I find a solution to the multiple call issue.

@SarnaMC
Copy link

SarnaMC commented Oct 25, 2017

My configuration (use xdebug)
{ "name": "Listen for XDebug", "type": "php", "log": true, "request": "launch", "port": 9000 }

Last log in Debug Console:
-> setBreakpointsRequest { command: 'setBreakpoints', arguments: { source: { path: '/var/www/html/drupal/drupal7/htdocs/sites/all/themes/contrib/my-theme/templates/search/blocks/block--views---exp-search-custom-article-page.tpl.php', name: 'block--views---exp-search-custom-article-page.tpl.php' }, lines: [ 2 ], breakpoints: [ { line: 2 } ], sourceModified: false }, type: 'request', seq: 14 }

The path is good, and debugging work on Atom so xdebug works

@jonyo
Copy link
Contributor Author

jonyo commented Oct 25, 2017

@SarnaMC I see the same thing.

I started debugging, I didn't get very far as I'm not familiar with debugging VSC extensions, I couldn't figure out where to put breakpoints and have it actually work lol...

What I did figure out, I believe the breakpoint requests are sent ASYNC so I think that just happens to be the "last thing" it sends, it may not necessarily be the thing that causes it to hang up. The last response it gets back before it hangs is this one...

<- threadsResponse
Response {
  seq: 0,
  type: 'response',
  request_seq: 9,
  command: 'threads',
  success: true,
  body: 
   { threads: 
      [ Thread { id: 1, name: 'Request 1 (1:02:39 PM)' },
        Thread { id: 2, name: 'Request 2 (1:02:39 PM)' } ] } }

My current working theory is maybe it just isn't set up to fork the connections, so maybe it has trouble keeping both connections open or something. It does seem to be keeping track of multiple connections, it just hangs up when trying to communicate with multiple ones at same time. If I can figure out how / where to add breakpoints (adding them in the main src/* files has no effect, adding them in out/* files has no effect either), I might be able to tell more.

@SarnaMC
Copy link

SarnaMC commented Oct 26, 2017

@jonyo funny but... after computer restart debug works perfectly. What have J done yesterday is J installed node 7.4.0 instead of 8.* and use command npm run compile. Now it works. Thank you @felixfbecker for your support, you are awesome!
J'm going back to work, J will test it all day

@RaulGRoque
Copy link

RaulGRoque commented Nov 27, 2017

The problem really is the multiple connections hitting it at the same time. Looks like this plugin do not support simultaneous connections.

I couldn't do it with this plugin, but the PHPStorm + Komodo DBGP proxy + some additional configurations in PHPStorm did the job. It works perfectly. If anyone is interested I can explain what I did.

Basically these links:
https://confluence.jetbrains.com/display/PhpStorm/Multi-user+debugging+in+PhpStorm+with+Xdebug+and+DBGp+proxy
https://confluence.jetbrains.com/display/PhpStorm/Simultaneous+debugging+sessions+with+PhpStorm

You need to uncheck both "Force break" options in the xDebug section in PHPStorm settings also.

@jonyo
Copy link
Contributor Author

jonyo commented Dec 4, 2017

@RaulGRoque That's the weird thing, looking at the code, it appears to be coded to handle multiple connections. It keeps track of multiple connections, for whatever reason it just doesn't handle it if multiple connections are happening at once.

@felixfbecker Do you have any tips how to get a breakpoint to work? Like I mentioned in a previous comment, I've tried adding breakpoints in the main code and in the generated code but neither one seems to make it actually pause at the line. I'm trying to add a breakpoint to the part where it is initially setting up the connection but it isn't working. Any help would be appreciated!

@felixfbecker
Copy link
Contributor

I would have to debug the code. It should work

@RaulGRoque
Copy link

@jonyo I only achived debugging multiple connections at once when I increased the number in the debug config of PHPStorm. I also unchecked the External Connections options and the XDebug ones like the image below:

msc

@felixfbecker
Copy link
Contributor

@RaulGRoque not to be that guy, but please keep the discussions in this repo around this debugger, not PHPStorm. Anyone can use whatever editor they want, but there are folks here (including me) that get notified on every comment and if it's about configuring PHPStorm then there are forums that are a better place than this ❤️

@RaulGRoque
Copy link

RaulGRoque commented Dec 4, 2017

As a side note, I accomplished debugging the backend application in my scenario putting it on an external XAMPP with a particular xDebug port. With the frontend and backend in separated XAMPPs and xDebug ports, the conflicts didn't happen using this plugin one application at a time. But it became messy and the only peaceful solution was this one that I posted above.

@felixfbecker It's ok. Thanks!

@felixfbecker
Copy link
Contributor

One big limitation of XDebug is that the whole protocol is synchronous. So while the program (on one Xdebug TCP connection) is running (I sent a run command) I cannot send any other request because I need to wait for the response first, which only comes after the program stopped again.

@carlosesilva
Copy link

I am also having this same issue when trying to debug phpunit tests
+1 for getting this fixed, pretty please =]

@gaainf
Copy link

gaainf commented Jan 6, 2018

For debugging any php code, which was started with exec/system/passthru functions It will be good to add "multiple connections" option to "Listen for XDebug" configuration in launch.json file.
+1

@jonagoldman
Copy link

jonagoldman commented Mar 17, 2018

I forgot that the debug session was already running so I clicked the green play button again (Start Debugging) and now it stopped working. Even when I restart the computer it does't work anymore.
I found the only way to "kind of" make it work is to send and additional request, now the first request will be stopped (but unusable) but I will be able to work with the second request. I will see both request threads in the Call Stack section of the extension. Could not find a way to make it work "normally" again.

image

only one request request is usable, the other is like frozen or something like that.

@elifiner
Copy link

elifiner commented Mar 27, 2018

Edit: the following is completely incorrect, keeping it here for posterity and for my own humility.

Looks like a simple configuration change is all that is needed to allow Xdebug to work with multiple sessions. All you need is to set the max_children setting to a high enough value. This is now my launch.json:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Listen for XDebug",
            "type": "php",
            "request": "launch",
            "port": 9000,
            "pathMappings": {
                "/var/www": "${workspaceRoot}",
            },
            "xdebugSettings": {
                "max_children": 20
            },
        },
    ]
}

The max_children setting seems to mirror a similar setting in PHPStorm mentioned above and it works flawlessly. I can now run Codeception acceptance tests and debug both the test code and the app code at the same time. YAY!

For reference here's my Xdebug configuration in php.ini:

zend_extension = xdebug.so
xdebug.remote_enable = 1
xdebug.remote_autostart = 1
xdebug.remote_port = 9000

@jonagoldman
Copy link

jonagoldman commented Mar 27, 2018

@elifiner from me it still behaves the same way as mentioned here #164 (comment)

Reading from the docs:
max_children: max number of array or object children to initially retrieve.

This does't seem to have anything to do with number of calls.

@brettjdicioccio
Copy link

@elifiner The max_children setting definitely helps with this issue. The site I am dealing with makes a whole lot of ajax requests so it has been very hard to debug. I see the following in the DEBUG console and am lucky if I get to my breakpoint: command is not availableread ECONNRESETwrite ECONNABORTEDwrite ECONNABORTEDread ECONNRESETread ECONNRESETread ECONNRESETread ECONNRESETread ....

@jonyo
Copy link
Contributor Author

jonyo commented Mar 28, 2018

@bdicioccio I think there may be a slight difference in your problem, for you it sounds like the multiple requests are being made by the browser. In my case, the additional request is made server-side. I don't see any errors like you do, just the normal debug notices, then it just hangs, it acts like it is getting into some kind of deadlock situation.

Too bad I thought maybe it was finally fixed...

Also, I believe what @jonagoldman said is correct, in theory that should just affect how much data it keeps track of by xdebug. If that fixes it for you, I wonder if somehow the default it is using for you is too high so it is running out of resources or something, so setting it to 20 is limiting it and keeping it from running out of memory. Just speculating 😄

@jonagoldman
Copy link

jonagoldman commented Mar 28, 2018

I suspect my problem might be related to CORS. An additional OPTIONS request is always sent before the actual request so on paper two requests are always made. The issue now is why this is causing the debugger to pause like there is a hidden break-point somewhere instead of ignoring the request and pausing on the actual break-point in the second request.

UPDATE 1: I can confirm this is part of the problem. I started Chrome with the --disable-web-security flag to avoid sending the additional OPTIONS requests, and now the debugger is not pausing when there are no breakpoints, most of the times. There are still occasions where it suddenly stops and there is no solution but to stop the debugger.

UPDATE 2: I am completely guessing here, but to me it seems that the debugger breaks when two requests are made almost simultaneously. This might explain why it breaks when CORS is used, and also why it sometimes works on multiple requests and sometimes it breaks, like I explained in above.

@svict4
Copy link

svict4 commented Aug 2, 2018

For anyone else coming across this thread: the answer described in this SO question fixed my error with multiple requests sent simultaneously freezing up VSCode/php debug.

@jonyo
Copy link
Contributor Author

jonyo commented Aug 14, 2018

Regarding the original problem, when the server itself is making the 2nd request using curl...

Its been a while since I tried, so thought I would have another go with debugging.

I added breakpoints at the point it is "writing" and point it is "reading" to/from the connection. I found a few interesting things:

  • Due to the order of things, it can sometimes send multiple commands before getting the response for the first command. I moved one line around and it fixed that but the problem persisted.
  • When debugging, for every message sent, it got a response. There is no "hanging" going on, at least not initially (perhaps it somehow hangs / gets deadlocked "before" the point it is trying to send a command, I'm going to investigate that angle further).
  • Rather than having the server make the request, I instead had 2 windows open and added a breakpoint in middle of hello world script, and loaded up both. It "seems" to work in that scenario so the problem seems unique to when one request makes a second request using curl, so that the first request isn't paused on a breakpoint but is waiting for a second request (which itself seems hung during the initialization or something)
  • I could be wrong but it seems to be sending the breakpoint refresh way too often. I tried adding a thing so that while it was still making the request to reload breakpoints, it would not process additional requests to reload breakpoints (in other words, prevent recursive breakpoint refreshes), that seemed to reduce the number of requests significantly. Also doing this seems to have made some kind of progress, if I hit "continue" a second time it now shows both requests as being paused on a breakpoint but it is still getting locked up at that point.

I'm still troubleshooting but I'll probably need to take a break soon to get some "actual" work done, just wanted to mention what I found so far in case it makes any sense to you @felixfbecker. If nothing else and I don't make any further progress I can put in a PR for the one bug fix that properly stops it from trying to send a second command until the first one is done.

edit: And I meant to make this clear: it is not the case that it is hung up because xdebug is sync instead of async. Like I said in point 2 it sent several commands for the 2nd connection and got responses, every command sent was getting a response. Something else odd is going on.

@jonyo
Copy link
Contributor Author

jonyo commented Aug 14, 2018

Got it working! I'll make a PR to fix.

So, when you send the run command (or step into, etc), xdebug basically doesn't do anything on that socket connection until it hits a breakpoint or the next line is run or whatever. So if the code it is running hangs up, say you add a sleep(30) and it runs that line... you won't get a response until that code is done.

In this scenario described, a new connection is being made during that time it is hung up running PHP code. When there is a new connection, vscode makes requests that basically reset all the breakpoints. But the way it is coded, it attempts to set the breakpoints on ALL connections and it waits for the results of all those calls. For the first connection, it ends up adding those calls to the queue, but it never gets to run them because it's waiting on that curl request, which is waiting on breakpoint calls... So it gets deadlocked.

@felixfbecker
Copy link
Contributor

@jonyo Awesome work!

felixfbecker pushed a commit that referenced this issue Aug 28, 2018
This introduces a new concept in the xDebug connection:  "execution commands": these are commands that result in PHP being executed.  The way xDebug works, if one of these commands is run, that connection is hung until the PHP code is done executing (until it gets to the next stopping point).  By keeping track of when such commands are still in progress, and making it something that the adapter can check, it allows the adapter to specifically code for when the connection is currently hung.  Which allows preventing the deadlock situation described in #164 

The adapter also now emits `before-execution-command` since it results in possibly going into a hung state for a while.  The adapter uses that event to send a `ContinueEvent`, this is just a side advantage that makes the interface more responsive.  Before when you click continue, if the PHP code is hung for whatever reason (it is slow, it has a lot to do, etc), it appears that it did not work as it appears to still be stopped on a breakpoint (but it is not, which you can tell by trying to view any of the details in the debug pane).  With the change, now when you click continue it immediately changes the process back to "running" state which is more truthful.

Since #164 has a lot of comments, here is the **tl;dr:** deadlock explanation: 
1. Connection 1 makes a second connection with curl.
2. It sends command to all connections to set breakpoints, and waits for response.
3. The second connection hangs as it is waiting for connection 1 to set breakpoints, connection 1 hangs without setting those breakpoints because it is waiting for connection 2 to respond and can't do anything until that completes.

This PR makes it not wait for the breakpoints to be set on a connection if the connection is waiting for code to execute.  So now connection 2 can finish initializing and run, no more deadlock.

Fixes #164
@felixfbecker
Copy link
Contributor

🎉 This issue has been resolved in version 1.12.5 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@sabman3
Copy link

sabman3 commented Aug 28, 2018

I know you said this was fixed in the latest release, but I'm not sure it is. I have two ajax calls for a page going to server. I see two process running in the debug window, however sometimes it does stop on the breakpoints while at other times it doesn't. Then on top of that even if I tell it to finish and the processes go away from the debug window, the browser freezes until I stop the debug.

{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Listen for XDebug",
"type": "php",
"request": "launch",
"port": 9000,
"stopOnEntry": true,
"xdebugSettings": {
"max_children": 20
}
}
]
}

@yavgech
Copy link

yavgech commented Sep 2, 2018

It now hangs when receiving a second Ajax request. My web page sends Ajax requests continuously.
Downgraded to version 1.12.4 and now it works great again.

towhidabsar pushed a commit to towhidabsar/vscode-php-debug that referenced this issue Sep 12, 2018
…ebug#294)

This introduces a new concept in the xDebug connection:  "execution commands": these are commands that result in PHP being executed.  The way xDebug works, if one of these commands is run, that connection is hung until the PHP code is done executing (until it gets to the next stopping point).  By keeping track of when such commands are still in progress, and making it something that the adapter can check, it allows the adapter to specifically code for when the connection is currently hung.  Which allows preventing the deadlock situation described in xdebug#164 

The adapter also now emits `before-execution-command` since it results in possibly going into a hung state for a while.  The adapter uses that event to send a `ContinueEvent`, this is just a side advantage that makes the interface more responsive.  Before when you click continue, if the PHP code is hung for whatever reason (it is slow, it has a lot to do, etc), it appears that it did not work as it appears to still be stopped on a breakpoint (but it is not, which you can tell by trying to view any of the details in the debug pane).  With the change, now when you click continue it immediately changes the process back to "running" state which is more truthful.

Since xdebug#164 has a lot of comments, here is the **tl;dr:** deadlock explanation: 
1. Connection 1 makes a second connection with curl.
2. It sends command to all connections to set breakpoints, and waits for response.
3. The second connection hangs as it is waiting for connection 1 to set breakpoints, connection 1 hangs without setting those breakpoints because it is waiting for connection 2 to respond and can't do anything until that completes.

This PR makes it not wait for the breakpoints to be set on a connection if the connection is waiting for code to execute.  So now connection 2 can finish initializing and run, no more deadlock.

Fixes xdebug#164
SidIcarus pushed a commit to towhidabsar/vscode-php-debug that referenced this issue Oct 9, 2018
…ebug#294)

This introduces a new concept in the xDebug connection:  "execution commands": these are commands that result in PHP being executed.  The way xDebug works, if one of these commands is run, that connection is hung until the PHP code is done executing (until it gets to the next stopping point).  By keeping track of when such commands are still in progress, and making it something that the adapter can check, it allows the adapter to specifically code for when the connection is currently hung.  Which allows preventing the deadlock situation described in xdebug#164 

The adapter also now emits `before-execution-command` since it results in possibly going into a hung state for a while.  The adapter uses that event to send a `ContinueEvent`, this is just a side advantage that makes the interface more responsive.  Before when you click continue, if the PHP code is hung for whatever reason (it is slow, it has a lot to do, etc), it appears that it did not work as it appears to still be stopped on a breakpoint (but it is not, which you can tell by trying to view any of the details in the debug pane).  With the change, now when you click continue it immediately changes the process back to "running" state which is more truthful.

Since xdebug#164 has a lot of comments, here is the **tl;dr:** deadlock explanation: 
1. Connection 1 makes a second connection with curl.
2. It sends command to all connections to set breakpoints, and waits for response.
3. The second connection hangs as it is waiting for connection 1 to set breakpoints, connection 1 hangs without setting those breakpoints because it is waiting for connection 2 to respond and can't do anything until that completes.

This PR makes it not wait for the breakpoints to be set on a connection if the connection is waiting for code to execute.  So now connection 2 can finish initializing and run, no more deadlock.

Fixes xdebug#164
SidIcarus pushed a commit to towhidabsar/vscode-php-debug that referenced this issue Oct 9, 2018
…ebug#294)

This introduces a new concept in the xDebug connection:  "execution commands": these are commands that result in PHP being executed.  The way xDebug works, if one of these commands is run, that connection is hung until the PHP code is done executing (until it gets to the next stopping point).  By keeping track of when such commands are still in progress, and making it something that the adapter can check, it allows the adapter to specifically code for when the connection is currently hung.  Which allows preventing the deadlock situation described in xdebug#164 

The adapter also now emits `before-execution-command` since it results in possibly going into a hung state for a while.  The adapter uses that event to send a `ContinueEvent`, this is just a side advantage that makes the interface more responsive.  Before when you click continue, if the PHP code is hung for whatever reason (it is slow, it has a lot to do, etc), it appears that it did not work as it appears to still be stopped on a breakpoint (but it is not, which you can tell by trying to view any of the details in the debug pane).  With the change, now when you click continue it immediately changes the process back to "running" state which is more truthful.

Since xdebug#164 has a lot of comments, here is the **tl;dr:** deadlock explanation: 
1. Connection 1 makes a second connection with curl.
2. It sends command to all connections to set breakpoints, and waits for response.
3. The second connection hangs as it is waiting for connection 1 to set breakpoints, connection 1 hangs without setting those breakpoints because it is waiting for connection 2 to respond and can't do anything until that completes.

This PR makes it not wait for the breakpoints to be set on a connection if the connection is waiting for code to execute.  So now connection 2 can finish initializing and run, no more deadlock.

Fixes xdebug#164
@devnix
Copy link

devnix commented Aug 2, 2019

For me, it hangs too when receiving an AJAX request. Still didn't try to downgrade.

@Zelfapp
Copy link

Zelfapp commented Sep 4, 2019

Running v 1.3.8.0

Any time there are 2 or more ajax calls php debugging hangs. Had to switch from vscode to phpstorm so I could debug. I didn't make any changes. Phpstorm works, vscode does not.

image

@jonyo
Copy link
Contributor Author

jonyo commented Sep 4, 2019

@Zelfapp By the way that sounds like a different issue, this one was a deadlock that happened when one request made a second request, it was not related to multiple ajax requests.

Also this one was resolved and closed over a year ago, you may get more traction creating a new issue or looking for a more recent issue that involves multiple ajax requests.

I see the confusion though if you only read the issue title it does sound related; since you are not the first to comment on it I'll update the title (if it lets me).

@jonyo jonyo changed the title Multiple calls make it hang Request making its own second request makes it hang Sep 4, 2019
@jonyo jonyo changed the title Request making its own second request makes it hang Request making a second request makes it hang Sep 4, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.