Common Swoole Questions

How to maintain a long running TCP connection?

With Swoole you can setup a TCP server or a HTTP server and use the following configuration options to maintain a long running TCP connection:

  • open_tcp_keepalive: Once set to true, you can use tcp_keepidle, tcp_keepcount, tcp_keepinterval
  • heartbeat_check_interval: You can enable this, defined in seconds allowing you to keep connections open longer, you also set heartbeat_idle_time as well


Restarting Swoole after modifying PHP code

With normal PHP programming and when using PHP-FPM everything is stateless, but when you use Swoole everything can be loaded intro memory and reused. However, this poses a problem, how can you use new code changes without having to restart an entire Swoole HTTP server for example.

In Swoole, it has support for asynchronous or hot code reloading when using workers. You can reload code on the go without having to restart the server and wait for workers to complete requests before restarting. This can only be done when you include PHP files after the onWorkerStart event, anything before the Swoole server or the actual Swoole runtime cannot be hot reloaded.

Please refer to the hot code reloading documentation.


Call to undefined function Co\run()

All coroutines in Swoole need to be wrapped inside a coroutine context, this context is automatically created for you when you use the HTTP Server for example.

However, if you receive errors saying Uncaught Error: Call to undefined function Co\run() or Uncaught Error: Call to undefined function go(), you must make sure you are on version v4.4.0 or above or include the namespace Swoole\Coroutine.

You can also use Swoole\Coroutine::create(callable $function, ...$args): int|false which is an alternative to go().


Can I share Redis or MySQL connections?

No, it is not possible to share one connection (Redis or MySQL) between multiple coroutines. It would not be possible to read or write at the same time using one connection.

You cannot share connections but you can keep them open or running via a connection pool. A connection pool allows you to store multiple connections that can be used by many coroutines and put back when they have been used and no longer needed, you can read more about connection pools here.


My connection has been closed errors

When using Swoole, especially the HTTP Server, you may come across the following messages in the console:

NOTICE swFactoryProcess_finish (ERRNO 1004): send 165 byte failed, because connection[fd=123] is closed

NOTICE swFactoryProcess_finish (ERROR 1005): connection[fd=123] does not exists

When seeing these messages, they are only notices and nothing to be worried about. These messages are shown due to one of the following:

  • The browser refreshes the page frantically (flashing before loading)
  • ab Canceled at half of the pressure test when benchmarking
  • wrk time-based pressure test (unfinished requests will be cancelled when the time is up)

The above situation and is normal, they are only notice messages.


Discarded Connection Errors

If you are receiving any of the following errors:

WARNING swWorker_discard_data (ERRNO 1007): [2] received the wrong data[21 bytes] from socket#75

WARNING Worker_discard_data (ERRNO 1007): [2] ignore data[5 bytes] received from session#2

This is something you should take a look into, the errors above mean you have a large number of connections being disconnected and probably need to check your configuration with discard_timeout_request option for the server.


Connection Refused

If you are receiving connection refused errors on your browser or client, it likely means you are not accessing the right IP address or port where you have your Swoole server running.

  • Make sure you have set the correct IP and port when running your Swoole server, check this with ps aux
  • Check if the port is actually listening with netstat -lp
  • Check that the network communication process is normal with tcpdump traceroute
  • Make sure you have no firewall rules setup which are blocking access


Resource temporarily unavailable

This error usually refers to the Swoole\Client module.

When getting the following error:

swoole_client::recv(): recv() failed. Error: Resource temporarily unavailable [11]

It indicates that the server did not return data within the specified time, and the connection timed out.

  • You can view the network communication process through tcpdump to check whether the server has sent data
  • The result of $serv->send() needs to be true
  • You may need to increase your server timeout


Worker exit timeout, forced to terminate

If you come across the following:

WARNING swWorker_reactor_try_to_exit (ERRNO 9012): worker exit timeout, forced to terminate

Indicates that the worker process did not exit within the agreed time (max_wait_time seconds), and Swoole forcibly terminates the worker process.

You should increase the timeout or make sure your workload can keep within the max_wait_time configuration option. However, this is only likely to be an issue when shutting down or restarting a server.


Unable to find callback function for signal Broken pipe

WARNING swSignalfd_onSignal (ERRNO 707): Unable to find callback function for signal Broken pipe: 13

Indicates that data is sent to a disconnected connection, usually because the return value of the send is not checked and the return fails and continues to send.


Object of class Swoole\Curl\Handler could not be converted to int

When using SWOOLE_HOOK_CURL you can encounter these errors:

PHP Notice:  Object of class Swoole\Curl\Handler could not be converted to int

PHP Warning: curl_multi_add_handle() expects parameter 2 to be resource, object given

When CURL is hooked it is no longer a resource type but an object type so the conversion to an int is not supported.

The best solution to get around this is to use SWOOLE_HOOK_NATIVE_CURL instead as Swoole now has full support for native CURL since v4.6.0.

You could also use Guzzle's SDK to replace the handler as well.


Guzzle 7.0+ outputting result directly to console

When using hooked coroutines and Guzzle 7.0 + at the same time, after initiating the request, the result will be directly output to the terminal.

Please update to at least v4.5.8 as this has been fixed.


No buffer space available

This error can be ignored. This error is that the socket_buffer_size option is too large, which is not accepted by individual systems, and does not affect the operation of the program.


Maximum GET request is 8192

The GET request has only one Http header. Swoole uses a fixed-size memory buffer of ​​8K, and it cannot be modified. If the request is not a correct Http request, an error will occur. The following error will be thrown:

WARN swReactorThread_onReceive_http_request: http header is too long.


POST file upload size

The maximum size is limited by the package_max_length, the default is 2M, you can call Server->set to pass in a new value to modify the size. Swoole runs in memory, so if it is set too large, it may cause a large number of concurrent requests to exhaust server resources.

It is probably best to chunk uploads instead when handling large files being uploaded.

Checking your installed Swoole configuration

Swoole is installed via a PHP PECL extension and requires you configure and compile before using Swoole in your application.

Because of this method of installing any PHP extension you may wish to check how you configured Swoole at a later date, to do this you can use php --ri swoole which will show something similar to:

swoole

Swoole => enabled
Author => Swoole Team <[email protected]>
Version => 4.4.16
Built => Mar 15 2020 20:40:05
coroutine => enabled
epoll => enabled
eventfd => enabled
signalfd => enabled
cpu_affinity => enabled
spinlock => enabled
rwlock => enabled
sockets => enabled
openssl => OpenSSL 1.1.1d  10 Sep 2019
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

Then you if need to reconfigure Swoole with different settings, you can use for example:

#!/bin/bash
pecl install --configureoptions 'enable-sockets="no" enable-openssl="yes" enable-http2="yes" enable-mysqlnd="yes" enable-swoole-json="no" enable-swoole-curl="yes"' swoole

More information is on the installation page.

Too many database/PDO connections open

If you are receiving errors related to too many open PHP PDO connections you either need to increase your max_connections in your MySQL config files to allow more DB connections to be created or make use of a connection pool. A connection pool allows you to reuse PDO connections after opening one, reducing the latency of creating and destroying a TCP database connection. When using a database connection pool you must make sure you put the connection back into the pool, otherwise that connection won't be able to be used again on another request, thus, being left open and results in the too many PDO connections errors.

You may encounter this error if you are opening a connection pool for each Swoole worker process, this will mean you have a pool for each worker, so if you have 4 workers and they all have 10 connections open, that is a total of 40 PDO connections open, you must then make sure your MySQL server supports this number of open connections.

PHP Fatal error: Uncaught Error: Call to undefined function Co\run()

You can enable Swoole shortname alias by modifying php.ini or swoole.ini and add the following line:

swoole.use_shortname=On

ERROR Swoole short name have to disable

You can disable Swoole shortname alias by modifying php.ini or swoole.ini and add the following line:

swoole.use_shortname=Off