laravel-s
laravel-s copied to clipboard
Abnormal exit or error is not restarting process, need to restart supervisor
- Your software version (Screenshot of your startup)
Run inside a docker container of ubuntu:latest
FROM ubuntu:latest
ARG WWWUSER=1000
ARG XDEBUG_HOST=host.docker.internal
ARG CONTAINER_ENV=production
ENV WWWUSER=1000
ENV XDEBUG_HOST=host.docker.internal
ENV CONTAINER_ENV=production
RUN useradd -ms /bin/bash -u ${WWWUSER} vessel
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
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
ENTRYPOINT ["start-container"]
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-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
supervisor.config
[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=root
redirect_stderr=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
+---------------------------+---------+ | Component | Version | +---------------------------+---------+ | PHP | 7.4.3 | | Swoole | 4.5.1 | | LaravelS | 3.7.3 | | Laravel Framework [local] | 6.18.16 | +---------------------------+---------+
root@a80ea3cc87a2:/var/www/html# php -m
[PHP Modules]
bcmath
calendar
Core
ctype
curl
date
dom
exif
FFI
fileinfo
filter
ftp
gd
gettext
hash
iconv
igbinary
imap
inotify
intl
json
ldap
libxml
mbstring
memcached
msgpack
mysqli
mysqlnd
openssl
pcntl
pcre
PDO
pdo_mysql
pdo_pgsql
pdo_sqlite
pgsql
Phar
posix
readline
redis
Reflection
sdebug
session
shmop
SimpleXML
soap
sockets
sodium
SPL
sqlite3
standard
swoole
sysvmsg
sysvsem
sysvshm
tokenizer
xml
xmlreader
xmlwriter
xsl
Zend OPcache
zip
zlib
[Zend Modules]
Sdebug
Zend OPcache
- Detail description about this issue(error/log)
If a Task or process gets the following error, the process is not restarted even if it should do that after 5s of abnormal exit.
_ _ _____
| | | |/ ____|
| | __ _ _ __ __ ___ _____| | (___
| | / _` | '__/ _` \ \ / / _ \ |\___ \
| |___| (_| | | | (_| |\ V / __/ |____) |
|______\__,_|_| \__,_| \_/ \___|_|_____/
Speed up your Laravel/Lumen
>>> Components
+---------------------------+---------+
| Component | Version |
+---------------------------+---------+
| PHP | 7.4.3 |
| Swoole | 4.5.1 |
| LaravelS | 3.7.3 |
| Laravel Framework [local] | 6.18.16 |
+---------------------------+---------+
>>> Protocols
+-----------+--------+-------------------+------------+
| Protocol | Status | Handler | Listen At |
+-----------+--------+-------------------+------------+
| Main HTTP | On | Laravel Framework | 0.0.0.0:80 |
+-----------+--------+-------------------+------------+
>>> Feedback: https://github.com/hhxsv5/laravel-s
[2020-05-29 18:39:44] [TRACE] Swoole is running, press Ctrl+C to quit.
[2020-05-29 18:40:33] [ERROR] Uncaught exception 'Exception': [0]Serialization of 'Closure' is not allowed called in /var/www/html/vendor/hhxsv5/laravel-s/src/Swoole/Task/BaseTask.php:93
#0 /var/www/html/vendor/hhxsv5/laravel-s/src/Swoole/Task/BaseTask.php(93): Swoole\Server->sendMessage()
#1 /var/www/html/vendor/hhxsv5/laravel-s/src/Swoole/Task/BaseTask.php(103): Hhxsv5\LaravelS\Swoole\Task\BaseTask->Hhxsv5\LaravelS\Swoole\Task\{closure}()
#2 /var/www/html/vendor/hhxsv5/laravel-s/src/Swoole/Task/Task.php(24): Hhxsv5\LaravelS\Swoole\Task\BaseTask->task()
#3 /var/www/html/app/Processes/WebSocketClientProcess.php(57): Hhxsv5\LaravelS\Swoole\Task\Task::deliver()
#4 [internal function]: App\Processes\WebSocketClientProcess::callback()
#5 /var/www/html/vendor/hhxsv5/laravel-s/src/Illuminate/LogTrait.php(82): call_user_func_array()
#6 /var/www/html/vendor/hhxsv5/laravel-s/src/Swoole/Process/CustomProcessTrait.php(57): Hhxsv5\LaravelS\LaravelS->callWithCatchException()
#7 {main}
PHP Fatal error: Uncaught ErrorException: Swoole\Server::start(): Unexpected end of serialized data in /var/www/html/vendor/hhxsv5/laravel-s/src/Swoole/Server.php:345
Stack trace:
#0 [internal function]: Illuminate\Foundation\Bootstrap\HandleExceptions->handleError()
#1 /var/www/html/vendor/hhxsv5/laravel-s/src/Swoole/Server.php(345): Swoole\Server->start()
#2 /var/www/html/vendor/hhxsv5/laravel-s/src/Console/Portal.php(153): Hhxsv5\LaravelS\Swoole\Server->run()
#3 /var/www/html/vendor/hhxsv5/laravel-s/src/Console/Portal.php(58): Hhxsv5\LaravelS\Console\Portal->start()
#4 /var/www/html/vendor/symfony/console/Command/Command.php(255): Hhxsv5\LaravelS\Console\Portal->execute()
#5 /var/www/html/bin/laravels(164): Symfony\Component\Console\Command\Command->run()
#6 {main}
thrown in /var/www/html/vendor/hhxsv5/laravel-s/src/Swoole/Server.php on line 345
PHP Stack trace:
PHP 1. {main}() /var/www/html/bin/laravels:0
PHP 2. Hhxsv5\LaravelS\Console\Portal->run() /var/www/html/bin/laravels:164
PHP 3. Hhxsv5\LaravelS\Console\Portal->execute() /var/www/html/vendor/symfony/console/Command/Command.php:255
PHP 4. Hhxsv5\LaravelS\Console\Portal->start() /var/www/html/vendor/hhxsv5/laravel-s/src/Console/Portal.php:58
PHP 5. Hhxsv5\LaravelS\LaravelS->run() /var/www/html/vendor/hhxsv5/laravel-s/src/Console/Portal.php:153
PHP 6. Swoole\Http\Server->start() /var/www/html/vendor/hhxsv5/laravel-s/src/Swoole/Server.php:345
Symfony\Component\Debug\Exception\FatalErrorException : Uncaught ErrorException: Swoole\Server::start(): Unexpected end of serialized data in /var/www/html/vendor/hhxsv5/laravel-s/src/Swoole/Server.php:345
Stack trace:
#0 [internal function]: Illuminate\Foundation\Bootstrap\HandleExceptions->handleError()
#1 /var/www/html/vendor/hhxsv5/laravel-s/src/Swoole/Server.php(345): Swoole\Server->start()
#2 /var/www/html/vendor/hhxsv5/laravel-s/src/Console/Portal.php(153): Hhxsv5\LaravelS\Swoole\Server->run()
#3 /var/www/html/vendor/hhxsv5/laravel-s/src/Console/Portal.php(58): Hhxsv5\LaravelS\Console\Portal->start()
#4 /var/www/html/vendor/symfony/console/Command/Command.php(255): Hhxsv5\LaravelS\Console\Portal->execute()
#5 /var/www/html/bin/laravels(164): Symfony\Component\Console\Command\Command->run()
#6 {main}
thrown
at /var/www/html/vendor/hhxsv5/laravel-s/src/Swoole/Server.php:345
341| }
342|
343| public function run()
344| {
> 345| $this->swoole->start();
346| }
347| }
348|
Exception trace:
1 Swoole\Http\Server::start()
/var/www/html/vendor/hhxsv5/laravel-s/src/Swoole/Server.php:345
2 Hhxsv5\LaravelS\LaravelS::run()
/var/www/html/vendor/hhxsv5/laravel-s/src/Console/Portal.php:153
Please use the argument -v to see more details.
Whoops\Exception\ErrorException : Uncaught ErrorException: Swoole\Server::start(): Unexpected end of serialized data in /var/www/html/vendor/hhxsv5/laravel-s/src/Swoole/Server.php:345
Stack trace:
#0 [internal function]: Illuminate\Foundation\Bootstrap\HandleExceptions->handleError()
#1 /var/www/html/vendor/hhxsv5/laravel-s/src/Swoole/Server.php(345): Swoole\Server->start()
#2 /var/www/html/vendor/hhxsv5/laravel-s/src/Console/Portal.php(153): Hhxsv5\LaravelS\Swoole\Server->run()
#3 /var/www/html/vendor/hhxsv5/laravel-s/src/Console/Portal.php(58): Hhxsv5\LaravelS\Console\Portal->start()
#4 /var/www/html/vendor/symfony/console/Command/Command.php(255): Hhxsv5\LaravelS\Console\Portal->execute()
#5 /var/www/html/bin/laravels(164): Symfony\Component\Console\Command\Command->run()
#6 {main}
thrown
at /var/www/html/vendor/hhxsv5/laravel-s/src/Swoole/Server.php:345
341| }
342|
343| public function run()
344| {
> 345| $this->swoole->start();
346| }
347| }
348|
Exception trace:
1 Whoops\Run::handleError()
/var/www/html/vendor/filp/whoops/src/Whoops/Run.php:408
2 Whoops\Run::handleShutdown()
[internal]:0
[2020-05-29 18:40:34] [ERROR] worker[5] error: exitCode=255, signal=0
[2020-05-29 18:40:40] [INFO] [Inotify] watched files: 9244; file types: .php,.env; excluded directories:
- Some
reproducible
code blocks andsteps
No code necessary, just do configs like this:
<?php
declare(strict_types = 1);
return [
'listen_ip' => '0.0.0.0',
'listen_port' => 80,
'socket_type' => env('SWOOLE_SOCKET_TYPE', 1),
'enable_coroutine_runtime' => false,
'server' => env('LARAVELS_SERVER', 'LaravelS'),
'handle_static' => env('LARAVELS_HANDLE_STATIC', false),
'laravel_base_path' => env('LARAVEL_BASE_PATH', base_path()),
'inotify_reload' => [
'enable' => env('LARAVELS_INOTIFY_RELOAD', false),
'watch_path' => base_path(),
'file_types' => ['.php', '.env'],
'excluded_dirs' => [],
'log' => true,
],
'event_handlers' => [],
'websocket' => [
'enable' => false,
],
'sockets' => [],
'processes' => [
'WebSocketProcess' => [
'class' => \App\Processes\WebSocketClientProcess::class,
'redirect' => false,
'pipe' => 0,
'enable' => true,
'queue' => [
'msg_key' => 0,
'mode' => 2,
'capacity' => 8192,
],
'restart_interval' => 5,
],
],
'timer' => [
'enable' => env('LARAVELS_TIMER', false),
'jobs' => [
// Enable LaravelScheduleJob to run `php artisan schedule:run` every 1 minute, replace Linux Crontab
\Hhxsv5\LaravelS\Illuminate\LaravelScheduleJob::class,
// Two ways to configure parameters:
// [\App\Jobs\XxxCronJob::class, [1000, true]], // Pass in parameters when registering
// \App\Jobs\XxxCronJob::class, // Override the corresponding method to return the configuration
],
'max_wait_time' => 5,
],
'swoole_tables' => [],
'register_providers' => [
\Laravel\Horizon\HorizonServiceProvider::class,
\App\Providers\AzureLogicAppsProvider::class,
\App\Providers\BroadcastServiceProvider::class,
\App\Providers\EventServiceProvider::class,
\App\Providers\RouteServiceProvider::class,
\App\Providers\AuthServiceProvider::class,
],
'cleaners' => [
// See LaravelS's built-in cleaners: https://github.com/hhxsv5/laravel-s/blob/master/Settings.md#cleaners
],
'destroy_controllers' => [
'enable' => false,
'excluded_list' => [
//\App\Http\Controllers\TestController::class,
],
],
'swoole' => [
'daemonize' => env('LARAVELS_DAEMONIZE', false),
'dispatch_mode' => 2,
'reactor_num' => env('LARAVELS_REACTOR_NUM', function_exists('swoole_cpu_num') ? swoole_cpu_num() * 2 : 4),
'worker_num' => env('LARAVELS_WORKER_NUM', function_exists('swoole_cpu_num') ? swoole_cpu_num() * 2 : 8),
'task_worker_num' => env(
'LARAVELS_TASK_WORKER_NUM',
function_exists('swoole_cpu_num') ? swoole_cpu_num() * 2 : 8
),
'task_ipc_mode' => 1,
'task_max_request' => env('LARAVELS_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' => storage_path('laravels.pid'),
'log_file' => storage_path(sprintf('logs/swoole-%s.log', date('Y-m-d'))),
'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' => 600,
'heartbeat_check_interval' => 60,
// Slow log
// 'request_slowlog_timeout' => 2,
// 'request_slowlog_file' => storage_path(sprintf('logs/slow-%s.log', date('Y-m'))),
// 'trace_event_worker' => true,
/*
* More settings of Swoole
* @see https://wiki.swoole.com/#/server/setting Chinese
* @see https://www.swoole.co.uk/docs/modules/swoole-server/configuration English
*/
],
];
and create processes with task, run inside task closure after error remove it and try var dumping something. It will not happen, service will be stuck.
I want to make swoole to always listen to WebSocket. Seems like after some time it becomes unresponsive and that's it. Websocket frames are sent, but swoole coroutine client is not picking up any frames anymore...
@juslintek The member properties of your task can only be in the limited types (boolean/integer/float/string/null/array/object), callable/resource cannot be serialized.
[2020-05-29 18:40:33] [ERROR] Uncaught exception 'Exception': [0]Serialization of 'Closure' is not allowed called in /var/www/html/vendor/hhxsv5/laravel-s/src/Swoole/Task/BaseTask.php:93
BTW, xdebug
conflicts with swoole
, they cannot be enabled at the same time.
I use sdebug the swoole compatible one. But one way or another it doesn't work... Is there any tool like xdebug for swoole?
P.S. problem is not the error I get. It is obvious. Its that processes after reload is not connecting to websocket again. Seems like callback is not happening anymore after reload or error. Here is process and task codes:
Process:
<?php
declare(strict_types=1);
namespace App\Processes;
use App\Services\DataloyApiClient;
use App\Tasks\FrameToNotificationConversion;
use Hhxsv5\LaravelS\Swoole\Process\CustomProcessInterface;
use Hhxsv5\LaravelS\Swoole\Task\Task;
use Swoole\Http\Server;
use Swoole\Process;
use Swoole\WebSocket\Frame;
use Swoole\Coroutine\HTTP\Client;
class WebSocketClientProcess implements CustomProcessInterface
{
/**
* @var bool Quit tag for Reload updates
*/
private static bool $quit = false;
private static string $accessToken = '';
private static Client $client;
public static function callback(Server $swoole, Process $process): void
{
$dataloyClient = new DataloyApiClient();
if (self::$accessToken === '') {
self::$accessToken = $dataloyClient->getAccessToken();
}
self::$client = new Client(
'socket-server',
80
);
self::$client->setHeaders([
'Host' => 'socket-server',
'User-Agent' => 'Chrome/49.0.2587.3',
'Accept' => 'application/json',
'Accept-Encoding' => 'gzip',
]);
self::$client->set(['timeout' => 1]);
$upgraded = self::$client->upgrade('/ws/rest/WebSocketAlertScriptRaw/COA/' . self::$accessToken);
if (!$upgraded) {
return;
}
while (!self::$quit) {
$frame = self::$client->recv();
if ($frame instanceof Frame) {
$task = new FrameToNotificationConversion($frame);
$task::deliver($task);
}
}
}
// Requirements: LaravelS >= v3.4.0 & callback() must be async non-blocking program.
public static function onReload(Server $swoole, Process $process): void
{
\Log::info('WebSocket Client process: reloading (' . self::$client->host . ')');
self::$quit = true;
self::$client->close();
}
}
Task:
<?php
declare(strict_types = 1);
namespace App\Tasks;
use App\Company;
use App\Notifications\ShipmentArrival;
use App\Services\DataloyApiClient;
use Hhxsv5\LaravelS\Swoole\Task\Task;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Notification;
use Swoole\WebSocket\Frame;
class FrameToNotificationConversion extends Task
{
private array $data;
private array $result = [];
public function __construct(Frame $frame)
{
$this->data = json_decode($frame->data, true);
}
// The logic of task handling, run in task process, CAN NOT deliver task
public function handle(): void
{
\Log::info(__CLASS__ . ':handle start', [$this->data]);
foreach ($this->data['cargos'] as $cargo) {
$cargoKey = $cargo['key'];
try {
$cargo = (new DataloyApiClient())
->get('Cargo', $cargoKey)
->fields(json_encode(
[
'cargoReference' => '',
'charterer' => [
'businessPartnerCode' => '',
'businessPartnerName' => '',
],
'cargoPorts' => [
'port' => [
'portName' => '',
],
'reasonForCall' => [
'reasonForCall' => '',
],
],
],
JSON_THROW_ON_ERROR | JSON_FORCE_OBJECT
))
->fetch();
} catch (\Exception $exception) {
\Log::error($exception->getMessage() . '. CargoKey:' . $cargoKey);
continue;
}
try {
$company = Company::where(
'dataloy_code',
$cargo->charterer->businessPartnerCode
)
->firstOrFail();
} catch (ModelNotFoundException $modelNotFoundException) {
\Log::notice(
$modelNotFoundException->getMessage()
. ' with dataloy_code = '
. $cargo->charterer->businessPartnerCode
. ' in '
. $modelNotFoundException->getFile()
. ':'
. $modelNotFoundException->getLine()
);
continue;
}
$messageData = [
'port_name' => $cargo->cargoPorts[1]->port->portName,
'shipment_id' => $cargo->cargoReference,
'action_url' => '/shipment/' . $cargo->cargoReference,
'new_eta' => $this->data['newETA'],
];
$this->result[] = $messageData;
Notification::send($company->users, new ShipmentArrival($messageData));
}
}
// Optional, finish event, the logic of after task handling, run in worker process, CAN deliver task
public function finish(): void
{
\Log::info(__CLASS__ . ':finish start', [$this->result]);
}
}
As far as I know, currently only sdebug. About the reload problem, I do not reproduce.
- WebSocketService
class WebSocketService implements WebSocketHandlerInterface
{
public function __construct()
{
}
public function onOpen(Server $server, Request $request)
{
$server->push($request->fd, 'Welcome to LaravelS[main]#' . $request->fd);
}
public function onMessage(Server $server, Frame $frame)
{
$server->push($frame->fd, 'LaravelS: ' . $frame->data);
}
public function onClose(Server $server, $fd, $reactorId)
{
}
}
- TestProcess
class TestProcess implements CustomProcessInterface
{
protected static $quit = false;
public static function callback(Server $swoole, Process $process)
{
\Log::info(__METHOD__ . ':start');
$cli = new Client('127.0.0.1', 5200);
$ret = $cli->upgrade('/');
if ($ret) {
while (!self::$quit) {
$cli->push('hello ' . date('Y-m-d H:i:s'));
$frame = $cli->recv();
Task::deliver(new TestWebSocketTask($frame));
Coroutine::sleep(1);
}
}
\Log::info(__METHOD__ . ':quit');
}
public static function onReload(Server $swoole, Process $process)
{
\Log::info('custom process: reloading');
self::$quit = true;
}
}
- TestWebSocketTask
class TestWebSocketTask extends Task
{
private $frame;
private $result;
public function __construct(Frame $frame)
{
$this->frame = $frame;
}
public function handle()
{
\Log::info(__METHOD__, [$this->frame->data]);
$this->result = 'the result: ' . microtime(true);
}
public function finish()
{
\Log::info(__METHOD__, [$this->result]);
}
}
- My Logs
bin/laravels reload at 2020-05-31 10:26:27.
[2020-05-31 10:26:10] local.INFO: App\Tasks\TestWebSocketTask::handle ["LaravelS: hello 2020-05-31 10:26:09"]
[2020-05-31 10:26:16] local.INFO: App\Processes\TestProcess::callback:start
[2020-05-31 10:26:16] local.INFO: App\Tasks\TestWebSocketTask::handle ["Welcome to LaravelS[main]#1"]
[2020-05-31 10:26:17] local.INFO: App\Tasks\TestWebSocketTask::handle ["LaravelS: hello 2020-05-31 10:26:16"]
[2020-05-31 10:26:18] local.INFO: App\Tasks\TestWebSocketTask::handle ["LaravelS: hello 2020-05-31 10:26:17"]
[2020-05-31 10:26:19] local.INFO: App\Tasks\TestWebSocketTask::handle ["LaravelS: hello 2020-05-31 10:26:18"]
[2020-05-31 10:26:20] local.INFO: App\Tasks\TestWebSocketTask::handle ["LaravelS: hello 2020-05-31 10:26:19"]
[2020-05-31 10:26:21] local.INFO: App\Tasks\TestWebSocketTask::handle ["LaravelS: hello 2020-05-31 10:26:20"]
[2020-05-31 10:26:22] local.INFO: App\Tasks\TestWebSocketTask::handle ["LaravelS: hello 2020-05-31 10:26:21"]
[2020-05-31 10:26:23] local.INFO: App\Tasks\TestWebSocketTask::handle ["LaravelS: hello 2020-05-31 10:26:22"]
[2020-05-31 10:26:24] local.INFO: App\Tasks\TestWebSocketTask::handle ["LaravelS: hello 2020-05-31 10:26:23"]
[2020-05-31 10:26:25] local.INFO: App\Tasks\TestWebSocketTask::handle ["LaravelS: hello 2020-05-31 10:26:24"]
[2020-05-31 10:26:26] local.INFO: App\Tasks\TestWebSocketTask::handle ["LaravelS: hello 2020-05-31 10:26:25"]
[2020-05-31 10:26:27] local.INFO: App\Tasks\TestWebSocketTask::handle ["LaravelS: hello 2020-05-31 10:26:26"]
[2020-05-31 10:26:27] local.INFO: custom process: reloading
[2020-05-31 10:26:28] local.INFO: App\Processes\TestProcess::callback:quit
[2020-05-31 10:26:35] local.INFO: App\Processes\TestProcess::callback:start
[2020-05-31 10:26:35] local.INFO: App\Tasks\TestWebSocketTask::handle ["Welcome to LaravelS[main]#2"]
[2020-05-31 10:26:36] local.INFO: App\Tasks\TestWebSocketTask::handle ["LaravelS: hello 2020-05-31 10:26:35"]
[2020-05-31 10:26:37] local.INFO: App\Tasks\TestWebSocketTask::handle ["LaravelS: hello 2020-05-31 10:26:36"]
[2020-05-31 10:26:38] local.INFO: App\Tasks\TestWebSocketTask::handle ["LaravelS: hello 2020-05-31 10:26:37"]
[2020-05-31 10:26:39] local.INFO: App\Tasks\TestWebSocketTask::handle ["LaravelS: hello 2020-05-31 10:26:38"]
@hhxsv5, But is WebSocket Service websocket client like new Websocket on javascript? Or WebSocket Server, like laravel-echo-server?
Because I currently need WebSocket as a client, not a service.
Maybe your wrapper cannot handle WebSocket clients?
Can you use my code, just without the processing complexity of data?
You can use this server for testing: https://www.websocket.org/echo.html
wss://echo.websocket.org
you can send any messages via the form at their website.
P.S. Have you used my Dockerfile?
I am adding composer.json in case:
{
"name": "juslintek/laravels-websocket-client",
"type": "project",
"description": "Swoole websocket client in laravel",
"keywords": [
"framework",
"laravel"
],
"license": "MIT",
"require": {
"php": "^7.4",
"ext-json": "*",
"fideloper/proxy": "^4.0",
"hhxsv5/laravel-s": "^3.7",
"laravel/framework": "^6.2",
"laravel/horizon": "^3.4",
"laravel/passport": "^8.0",
"laravel/socialite": "^4.3",
"laravel/tinker": "^1.0",
"predis/predis": "^1.1",
"rennokki/laravel-eloquent-query-cache": "^1.3",
"socialiteproviders/microsoft-azure": "^3.0",
"spatie/enum": "^2.3",
"spatie/laravel-responsecache": "^6.5"
},
"require-dev": {
"barryvdh/laravel-ide-helper": "^2.6",
"codedungeon/phpunit-result-printer": "^0.26.2",
"eaglewu/swoole-ide-helper": "dev-master",
"facade/ignition": "^1.4",
"fzaninotto/faker": "^1.4",
"laravel/homestead": "^9.4",
"laravel/telescope": "^3.5",
"laravel/ui": "^1.1",
"mockery/mockery": "^1.0",
"nunomaduro/collision": "^3.0",
"nunomaduro/larastan": "^0.5.8",
"nunomaduro/phpinsights": "^1.9",
"phpmd/phpmd": "^2.8",
"phpstan/phpstan": "^0.12",
"phpunit/phpunit": "^8.0",
"symplify/easy-coding-standard": "^7.0",
"yurunsoft/guzzle-swoole": "^2.1"
},
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"sort-packages": true
},
"extra": {
"laravel": {
"dont-discover": [
"laravel/socialite"
]
}
},
"autoload": {
"psr-4": {
"App\\": "app/"
},
"classmap": [
"database/seeds",
"database/factories"
]
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
},
"minimum-stability": "dev",
"prefer-stable": true,
"scripts": {
"phpstan:test": "phpstan analyze --ansi --memory-limit=1G",
"phpunit:test": "phpunit --colors=always",
"ecs:test": "ecs check app tests",
"ecs:fix": "ecs check --fix app tests",
"php-cs-fixer:fix": "php-cs-fixer fix --config=.php_cs -v --using-cache=no ./app ./tests ./routes ./database",
"insights:test": "php artisan insights --no-interaction",
"test": [
"@insights:test",
"@phpunit:test"
],
"ide-helper:generate": [
"php artisan ide-helper:generate",
"php artisan ide-helper:meta",
"php artisan ide-helper:models --nowrite"
],
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi"
],
"post-root-package-install": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
],
"post-create-project-cmd": [
"@php artisan key:generate --ansi"
],
"post-update-cmd": "@ide-helper:generate"
}
}
And as well .env file:
APP_PORT=80
MYSQL_PORT=3306
IGNITION_THEME=dark
APP_NAME=Laravel
APP_ENV=local
APP_KEY= # generate your own code
APP_DEBUG=true
APP_URL=http://localhost
#APP_RUNNING_IN_CONSOLE=false
MIX_SENTRY_DSN_PUBLIC="localhost"
LOG_CHANNEL=stack
# run MySQL container for that.
DB_CONNECTION=mysql
DB_HOST=mysql #docker MySQL container
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=secret
REDIS_CLIENT=phpredis
REDIS_HOST=redis #docker redis container
REDIS_PASSWORD=null
REDIS_PORT=6379
REDIS_CACHE_DB=2
REDIS_QUEUES_DB=3
REDIS_HORIZON_CONNECTION=default
REDIS_PREFIX=
BROADCAST_DRIVER=redis
CACHE_DRIVER=redis
QUEUE_CONNECTION=redis
SESSION_DRIVER=redis
SESSION_LIFETIME=120
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
TELESCOPE_ENABLED=true
PASSPORT_LOGIN_URL=${APP_URL}/oauth/token
PASSPORT_CLIENT_ID= #genrate your own
PASSPORT_CLIENT_SECRET= #genrate your own
PHP_IDE=phpstorm
LARAVEL_ECHO_SERVER_AUTH_HOST=http://localhost
LARAVEL_ECHO_SERVER_REDIS_HOST=${REDIS_HOST}
LARAVEL_ECHO_SERVER_REDIS_PORT=${REDIS_PORT}
MIX_SOCKETIO_APP_ID=
MIX_SOCKETIO_APP_KEY=
HORIZON_BASIC_AUTH_USERNAME=
HORIZON_BASIC_AUTH_PASSWORD=
LARAVELS_INOTIFY_RELOAD=true
LARAVELS_LISTEN_IP=0.0.0.0
LARAVELS_LISTEN_PORT=80
LARAVELS_TIMER=true
SWOOLE_SOCKET_TYPE=1
LARAVELS_REACTOR_NUM=2
LARAVELS_WORKER_NUM=4
LARAVELS_TASK_WORKER_NUM=4
UPDATE
Seems like it stops listening after the 60s or something and you have to manually restart service in order for socket to continue listening.
UPDATE: Guess it was more of a swoole thing. Solved it by changing heartbeat check interval and hearbeat_idle_time: config/laravels.php
'swoole' => [
// ...
'heartbeat_idle_time' => 60,
'heartbeat_check_interval' => 10,
// ...
],
Guess to prevent also tried this in the loop:
while (!self::$quit) {
$frame = self::$client->recv();
if ($frame instanceof Frame) {
$task = new FrameToNotificationConversion($frame);
$task::deliver($task);
}
if (!self::$client->connected) {
self::$quit = true;
}
}
and it worked. This one creates rapid reconnect, can change networks whatever you want. Very persistent. :-) Even better than health checks. :-) Basically reruns process a new. Can even put your computer to sleep run back again and bam its running and listening to socket. :D
Super awesome.
@juslintek According to the Swoole documentation, after 4.x, the connected
property is no longer updated in real time and is no longer reliable. So I suggest to use errCode
as the connection status judgment.
while (!self::$quit) {
$frame = self::$client->recv();
if (!self::$client->errCode) {
Log::error('An error occurred', [$client->errCode, $client->errMsg]);
self::$quit = true;
}
if ($frame instanceof Frame) {
$task = new FrameToNotificationConversion($frame);
$task::deliver($task);
}
}
@hhxsv5 thank you very much, I will change code accordingly. :-)
@hhxsv5 When this process runs for a very long time, ./bin/laravels
stop doesn't kill it. It continues working in the background unless you add timeouts to the connection, then it waits for a connection to timeout and after that gets killed, but if the connection is continuous like WebSocket, then does not get interrupted and killed. So the only way to kill it is with:
kill -9 PID
I thought that onStop it will get killed. But it doesn't.
I see one solution is to use the client as a static property for the whole process. And onStop, close its connection.
What do you think? Do I need to send some keepalive or ping pong to check if the connection is running? I basically need to stop it instantly on-demand.
I'm running laravel-s and trying to implement sdebug, could you guys assist on this?
Its seems to be connecting to my vscode but it drops right after. is there any specific configuration I need to change?
@juber-ivre, Sdebug works only with phpunit. :-) Or first request in requests sequence or I assume it gets clogged somewhere and cannot trace requests. You can check my issues related to sdebug. Basically if you retry request from dev tools network it usually hits the breakpoint. But you do page reload it gets ignored. After it gets ignored you have to restart laravels process. Then again you can catch sdebug responses on breakpoints.