swoole / swoole-src

🚀 Coroutine-based concurrency library for PHP
https://www.swoole.com
Apache License 2.0
18.4k stars 3.16k forks source link

Sdebug not stopping at breakpoint when preset IDE key is used in PHP xdebug config and PhpStorm Remote Debug #3421

Closed juslintek closed 3 years ago

juslintek commented 4 years ago

Please answer these questions before submitting your issue. Thanks!

  1. What did you do? If possible, provide a simple script for reproducing the error. I use laravel-s wrapper for Swoole PHP extension. Swoole is latest installed. I have my infrastructure setup in docker, using docker-compose. Xdebug is set to use host.docker.internal which is at entrypoint.sh resolved if not exist in operating system to docker containers default gateway. Basically here are sdebug configs.

xdebug.ini

zend_extension=xdebug.so
xdebug.remote_enable=on
xdebug.remote_autostart=on
xdebug.remote_connect_back=off
xdebug.remote_handler=dbgp
xdebug.remote_port=9000
xdebug.idekey=DOCKER-MYG2-BACKEND
xdebug.remote_host=host.docker.internal
xdebug.max_nesting_level=500
xdebug.profiler_enable_trigger=on
xdebug.profiler_output_dir=/var/www/html/storage/cache/xdebug-profiles/
;xdebug.remote_log=/var/www/html/storage/logs/xdebug-remote.log
xdebug.profiler_output_name=cachegrind.out.%R.%p

image image image

  1. What did you expect to see? I expect when the request is sent to URI, it breaks at the breakpoint of an action which is the underlying function for endpoint.

  2. What did you see instead? I go no reaction at all. It just skips Sdebug at all. But when I run that remote debug configurations before swoole process start it never starts, even though that controller is not even triggered.

  3. What version of Swoole are you using (show your php --ri swoole)?

swoole

Swoole => enabled Author => Swoole Team team@swoole.com Version => 4.5.2 Built => Jun 23 2020 14:59:52 coroutine => enabled epoll => enabled eventfd => enabled signalfd => enabled cpu_affinity => enabled spinlock => enabled rwlock => enabled sockets => enabled openssl => OpenSSL 1.1.1f 31 Mar 2020 http2 => enabled pcre => enabled mutex_timedlock => enabled pthread_barrier => enabled futex => enabled mysqlnd => enabled async_redis => enabled

Directive => Local Value => Master Value swoole.enable_coroutine => On => On swoole.enable_library => On => On swoole.enable_preemptive_scheduler => Off => Off swoole.display_errors => On => On swoole.use_shortname => On => On swoole.unixsock_buffer_size => 8388608 => 8388608


5. What is your machine environment used (including version of kernel & php & gcc) ?
```bash
root@7f45c44f4581:/var/www/html# cat /etc/issue
Ubuntu 20.04 LTS \n \l
root@7f45c44f4581:/var/www/html# uname -a
Linux 7f45c44f4581 4.19.76-linuxkit #1 SMP Tue May 26 11:42:35 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
root@7f45c44f4581:/var/www/html# php -v
PHP 7.4.3 (cli) (built: May 26 2020 12:24:22) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Zend OPcache v7.4.3, Copyright (c), by Zend Technologies
    with Sdebug v2.9.3-dev, Copyright (c) 2002-2020, by Derick Rethans
root@7f45c44f4581:/var/www/html# gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:hsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 9.3.0-10ubuntu2' --with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,gm2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-9 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none,hsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 9.3.0 (Ubuntu 9.3.0-10ubuntu2) 

I'm providing Dockefile itself:

FROM ubuntu:latest

ARG HOST_USER=1000
ARG HOST_GROUP=1000
ARG XDEBUG_HOST=host.docker.internal
ARG CONTAINER_ENV=production
ARG APP_URL=myg2.test

ENV USER ${HOST_USER:-1000}
ENV GROUP ${HOST_GROUP:-1000}
ENV XDEBUG_HOST "${XDEBUG_HOST:-host.docker.internal}"
ENV CONTAINER_ENV "${CONTAINER_ENV:-production}"
ENV APP_URL "${APP_URL:-http://myg2.test}"

RUN if getent group ${GROUP} > /dev/null 2>&1; then groupmod -g 9999 $(getent group ${GROUP} | cut -d: -f1); fi \
    && if getent passwd ${USER} > /dev/null 2>&1; then usermod -u 9999 $(getent passwd ${USER} | cut -d: -f1); fi \
    && groupadd -g ${GROUP} vessel \
    && useradd -ms /bin/bash -u ${USER} -g ${GROUP} vessel -G tty

WORKDIR /var/www/html

ENV TZ=UTC
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

RUN set -x \
    && apt-get update \
    && apt-get install -y \
        gnupg \
        gosu \
        curl \
        dos2unix \
        inotify-tools \
        iputils-ping \
        iproute2 \
        zip \
        unzip \
        openssl \
        libssl-dev \
        git \
        supervisor \
        sqlite3 \
    && gosu nobody true

RUN apt-get install -y \
    php-dev \
    php-cli \
    php-pgsql \
    php-sqlite3 \
    php-gd \
    php-curl \
    php-memcached \
    php-imap \
    php-mysql \
    php-mbstring \
    php-xml \
    php-zip \
    php-bcmath \
    php-soap \
    php-intl \
    php-readline \
    php-msgpack \
    php-igbinary \
    php-ldap \
    php-redis

RUN pecl install -a --nobuild swoole \
    && cd "$(pecl config-get temp_dir)/swoole" \
    && phpize \
    && ./configure --enable-sockets --enable-openssl --enable-http2 --enable-mysqlnd \
    && make \
    && make install \
    && echo "extension=swoole.so" >> $(php -i | grep "php.*php.ini" | rev | cut -d' ' -f1 | rev)

RUN pecl install inotify \
    && echo "extension=inotify.so" >> $(php -i | grep "php.*php.ini" | rev | cut -d' ' -f1 | rev)

RUN git clone https://github.com/swoole/sdebug.git \
    && cd sdebug \
    && ./rebuild.sh \
    && cd .. \
    && rm -rf sdebug

RUN php -r "readfile('http://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer \
    && apt-get -y autoremove \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

COPY xdebug.ini /etc/php/7.4/cli/conf.d/20-xdebug.ini
COPY vessel.ini /etc/php/7.4/cli/conf.d/99-vessel.ini

EXPOSE 80

COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY start-container /usr/local/bin/start-container
RUN dos2unix /usr/local/bin/start-container \
    && chmod +x /usr/local/bin/start-container

RUN ln -snf /var/www/html/storage/logs/laravels.log /dev/stdout

ENTRYPOINT ["start-container"]

start-container.sh

#!/usr/bin/env bash

# Config /etc/php/7.4/mods-available/xdebug.ini

DOCKER_ROUTE_DEFAULT=$(/sbin/ip route | awk '/default/ { print $3 }')
DOCKER_HOSTNAME="host.docker.internal"

if ping -c 1 $DOCKER_HOSTNAME &> /dev/null; then
    echo "Using $DOCKER_HOSTNAME for xdebug remote host"
else
    echo "Using $DOCKER_ROUTE_DEFAULT for xdebug remote host"
    ip -4 route list match 0/0 | awk "{print \$3\" ${DOCKER_HOSTNAME}\"}" >> /etc/hosts
fi

# Ensure /.composer exists and is writable
if [ ! -d /.composer ]; then
    mkdir /.composer
fi
chmod -R ugo+rw /.composer

# Run a command or supervisord
if [ $# -gt 0 ]; then
    # If we passed a command, run it as current user
    exec gosu "${USER}" "$@"
else
    # Otherwise start supervisord
    /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
fi

vessel.ini

[PHP]

; Maximum allowed size for uploaded files.
; http://php.net/upload-max-filesize
upload_max_filesize = 100M

; Maximum size of POST data that PHP will accept.
; Its value may be 0 to disable the limit. It is ignored if POST data reading
; is disabled through enable_post_data_reading.
; http://php.net/post-max-size
post_max_size = 100M

supervisord.conf

[supervisord]
nodaemon=true
user=root

[program:horizon]
process_name=%(program_name)s
command=php /var/www/html/artisan horizon
autostart=true
autorestart=true
user=vessel
redirect_stderr=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stopwaitsecs=3600

[program:swoole]
process_name=%(program_name)s
directory=/var/www/html/
command=bin/laravels start -i
numprocs=1
autostart=true
autorestart=true
startretries=3
user=vessel
redirect_stderr=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0

just init new laravel project and install laravel-s run php artisan laravels publish

then add these configs to config/ dir of new laravel project init: laravels.php

<?php

/**
 * @see https://github.com/hhxsv5/laravel-s/blob/master/Settings.md  English
 */

declare(strict_types=1);

return [
    'listen_ip' => '127.0.0.1',
    'listen_port' => 5200,
    'socket_type' => 5,
    'enable_coroutine_runtime' => false,
    'server' => 'TEST',
    'handle_static' => false,
    'laravel_base_path' => base_path(),
    'inotify_reload' => [
        'enable' => false,
        'watch_path' => base_path(),
        'file_types' => ['.php'],
        'excluded_dirs' => [],
        'log' => true,
    ],
    'event_handlers' => [],
    'websocket' => [
        'enable' => false,
    ],
    'sockets' => [],
    'processes' => []
    'timer' => [
        'enable' => false,
        'jobs' => [],
        'max_wait_time' => 5,
    ],
    'swoole_tables' => [],
    'register_providers' => [],
    'cleaners' => [],
    'destroy_controllers' => [
        'enable' => false,
        'excluded_list' => [],
    ],
    'swoole' => [
        'daemonize' => false,
        'dispatch_mode' => 2,
        'reactor_num' => function_exists('swoole_cpu_num') ? swoole_cpu_num() * 2 : 4,
        'worker_num' => function_exists('swoole_cpu_num') ? swoole_cpu_num() * 2 : 8,
        'task_worker_num' => function_exists('swoole_cpu_num') ? swoole_cpu_num() * 2 : 8,
        'task_ipc_mode' => 1,
        'task_max_request' => 8000,
        'task_tmpdir' => is_writable('/dev/shm/') ? '/dev/shm' : '/tmp',
        'max_request' => env('LARAVELS_MAX_REQUEST', 8000),
        'open_tcp_nodelay' => true,
        'pid_file' => env('LARAVELS_PID_FILE', storage_path('laravels.pid')),
        'log_file' => env('LARAVELS_LOG_FILE', storage_path('logs/laravels.log')),
        'log_level' => 1,
        'document_root' => base_path('public'),
        'buffer_output_size' => 2 * 1024 * 1024,
        'socket_buffer_size' => 128 * 1024 * 1024,
        'package_max_length' => 4 * 1024 * 1024,
        'reload_async' => true,
        'max_wait_time' => 60,
        'enable_reuse_port' => true,
        'enable_coroutine' => true,
        'http_compression' => true,
        'heartbeat_idle_time' => 30,
        'heartbeat_check_interval' => 10,
        'log_rotation' => 0,
        'discard_timeout_request' => false,
    ],
];

And in routes/api.php add

Route::get('test', static function(Request $request) {
     if ($request) { // <-- break here
           $variableToCheckBeforeBreak = $request;
     }

     return response()->json(['data' => $request->all()])
});

run bin/laravels start check it locally or run my Dockerfile with 5200 port exposed and use in configs port 5200 instead of 80 as I do. Because in my setup swoole is under Nginx proxy.

juslintek commented 4 years ago

Okay fixed this. I guess nginx cannot proxy xdebug headers or something related to it. So I had to Nginx and expose port to swoole container itself and it worked. End results screenshot: image app is /etc/hosts map to 127.0.0.1, which docker DNS resolves to the actual container.

juslintek commented 4 years ago

So it seems that when runtime coroutines are enabled it doesn't work.

amuluowin commented 4 years ago

You should export the env PHP_IDE_CONFIG="serverName=your server name like myg2-app"

juslintek commented 4 years ago

@amuluowin when I set this inside docker as the environmental variable PHP_IDE_CONFIG="serverName=myg2-app" it is found there, but still it doesn't work xdebug log says:

[747] Log opened at 2020-07-17 10:30:20
[747] I: Connecting to configured address/port: host.docker.internal:9000.
[747] W: Creating socket for 'host.docker.internal:9000', poll success, but error: Operation now in progress (29).
[747] E: Could not connect to client. :-(
[747] Log closed at 2020-07-17 10:30:20

[752] Log opened at 2020-07-17 10:30:42
[752] I: Connecting to configured address/port: host.docker.internal:9000.
[752] W: Creating socket for 'host.docker.internal:9000', poll success, but error: Operation now in progress (29).
[752] E: Could not connect to client. :-(
[752] Log closed at 2020-07-17 10:30:42

If I switch back to php-fpm and xdebug it works even without the above variable.

And PhpStorm doesn't break on that point, just hangs response.

huanghantao commented 3 years ago

We recommend using https://github.com/swoole/yasd to debug

juslintek commented 3 years ago

We recommend using https://github.com/swoole/yasd to debug

It doesn't work with phpstorm and vscode and probably with php8.