<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Kristjan Siimson</title>
    <description>The latest articles on Forem by Kristjan Siimson (@siimsoni).</description>
    <link>https://forem.com/siimsoni</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F306221%2F0ae54c37-b638-48f4-a159-8337eb889ea1.jpeg</url>
      <title>Forem: Kristjan Siimson</title>
      <link>https://forem.com/siimsoni</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/siimsoni"/>
    <language>en</language>
    <item>
      <title>3 tips for performant PHP code</title>
      <dc:creator>Kristjan Siimson</dc:creator>
      <pubDate>Tue, 07 Jul 2020 13:32:29 +0000</pubDate>
      <link>https://forem.com/siimsoni/3-tips-for-performant-php-code-4n7j</link>
      <guid>https://forem.com/siimsoni/3-tips-for-performant-php-code-4n7j</guid>
      <description>&lt;h2&gt;
  
  
  Disclaimer
&lt;/h2&gt;

&lt;p&gt;This is an advanced post about performance optimization. Don't blindly take this advice. Not all projects prioritize performance. If you are not familiar with the mentioned language features, take your time to understand them.&lt;/p&gt;

&lt;h2&gt;
  
  
  (1) Know your language constructs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;isset($array['key'])&lt;/code&gt; over &lt;code&gt;array_key_exists('key', $array)&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Reasoning
&lt;/h3&gt;

&lt;p&gt;Faster than function calls. There are two language constructs that particularly useful, which are &lt;a href="https://www.php.net/manual/en/function.isset.php"&gt;&lt;code&gt;isset()&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://www.php.net/manual/en/function.empty.php"&gt;&lt;code&gt;empty()&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;[Pitfalls] &lt;code&gt;empty()&lt;/code&gt; uses type juggling, see next section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Opcodes
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;if(isset($array['key'])) {}&lt;/code&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;op&lt;/th&gt;
&lt;th&gt;return&lt;/th&gt;
&lt;th&gt;operands&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ISSET_ISEMPTY_DIM_OBJ&lt;/td&gt;
&lt;td&gt;~1&lt;/td&gt;
&lt;td&gt;!0, 'key'&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JMPZ&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;~1, -&amp;gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;if(array_key_exists('key', $array)) {}&lt;/code&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;op&lt;/th&gt;
&lt;th&gt;return&lt;/th&gt;
&lt;th&gt;operands&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;INIT_FCALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;'array_key_exists'&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEND_VAL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;'key'&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEND_VAL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;!0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DO_ICALL&lt;/td&gt;
&lt;td&gt;$2&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JMPZ&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;$2, -&amp;gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  (2) Don't fight the type system (but learn it first)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;if($arr) {}&lt;/code&gt; over &lt;code&gt;if(count($arr) &amp;gt; 0) {}&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Reasoning
&lt;/h3&gt;

&lt;p&gt;Using &lt;a href="https://www.php.net/manual/en/language.types.type-juggling.php"&gt;type juggling&lt;/a&gt; reduces redundant opcodes, and therefore also memory allocations.&lt;/p&gt;

&lt;p&gt;[Pitfalls] &lt;a href="https://owasp.org/www-pdf-archive/PHPMagicTricks-TypeJuggling.pdf"&gt;PHP Magic Tricks: Type Juggling&lt;/a&gt; presentation by Insomnia Security outlines some example security exploits enabled by inappropriate use of type juggling. Perhaps the most surprising behavior is exhibited in string to integer conversion, e.g. &lt;code&gt;"0e768261251903820937390661668547" == "0"&lt;/code&gt;. This is intentional and &lt;a href="https://www.php.net/manual/en/language.types.string.php#language.types.string.casting"&gt;well documented&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Opcodes
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;if($arr) {}&lt;/code&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;op&lt;/th&gt;
&lt;th&gt;return&lt;/th&gt;
&lt;th&gt;operands&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;JMPZ&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;!0, -&amp;gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;if(count($arr) &amp;gt; 0) {}&lt;/code&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;op&lt;/th&gt;
&lt;th&gt;return&lt;/th&gt;
&lt;th&gt;operands&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;COUNT&lt;/td&gt;
&lt;td&gt;~1&lt;/td&gt;
&lt;td&gt;!0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IS_SMALLER&lt;/td&gt;
&lt;td&gt;~2&lt;/td&gt;
&lt;td&gt;0, ~1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JMPZ&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;~2, -&amp;gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  (3) Clean up your variables
&lt;/h2&gt;

&lt;p&gt;PHP does some nifty behind-the-scenes optimizations, and this tip is to let it do it’s job. One of the tricks PHP does is related to passing variables by value, rather than reference. PHP will optimize away assignments if the value is not assigned to any other variable, and the value doesn't change.&lt;/p&gt;

&lt;h3&gt;
  
  
  First example ✔️ -
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="nv"&gt;$var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// do something&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$var&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here the value is assigned in the variable assignment. Even though the value is passed by value, there is actually only one assignment, because the value doesn't change.&lt;/p&gt;

&lt;h3&gt;
  
  
  Second example ⚠️ -
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="nv"&gt;$var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// do something&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$var&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here the value changes and therefore there are two assignments, one in the main scope and another inside the function.&lt;/p&gt;

&lt;h3&gt;
  
  
  Third example ✔️ -
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// do something&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'b'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this example, the value is assigned just before calling &lt;code&gt;a()&lt;/code&gt;, and since nothing holds reference to it, PHP can mutate the value, instead of making another assignment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reasoning
&lt;/h3&gt;

&lt;p&gt;This is not something to worry so much about when the values are small, but I’ve caught some OOM situations where the root cause was an useless variable. This also helps the garbage collector, which only cleans up the values that are not referenced by any variables.&lt;/p&gt;

</description>
      <category>php</category>
    </item>
    <item>
      <title>Timeout strategies in PHP + MySQL application</title>
      <dc:creator>Kristjan Siimson</dc:creator>
      <pubDate>Sun, 05 Jul 2020 15:41:57 +0000</pubDate>
      <link>https://forem.com/siimsoni/timeout-strategies-in-php-mysql-application-30fb</link>
      <guid>https://forem.com/siimsoni/timeout-strategies-in-php-mysql-application-30fb</guid>
      <description>&lt;h1&gt;
  
  
  Application hanged
&lt;/h1&gt;

&lt;p&gt;I’ll start by describing a situation that prompted me to explore topic of timeouts. I worked with a typical PHP and MySQL application. The server receives a HTTP request, passes it to PHP using FastCGI interface, PHP establishes a connection to MySQL database, and application then executes queries over the connection.&lt;/p&gt;

&lt;p&gt;Client&lt;br&gt;
| (HTTPS:443)&lt;br&gt;
Server&lt;br&gt;
| (FastCGI:9000)&lt;br&gt;
PHP-FPM&lt;br&gt;
| (mysqli:3306)&lt;br&gt;
MySQL&lt;/p&gt;

&lt;p&gt;The problem I encountered was related to communication between PHP and MYSQL. The application was hanging until server timed out the request. An investigation revealed a hanging query and MySQL, which caused queries on a certain table to hang indefinitely. &lt;/p&gt;
&lt;h1&gt;
  
  
  Problems
&lt;/h1&gt;

&lt;p&gt;Apart from the obvious problem that the application was hanging, the available processes can quickly be used up. A malicious actor can exploit this in a denial-of-service attack. Also, small issues, such as a single endpoint failing, can quickly snowball into all endpoints failing.&lt;/p&gt;

&lt;p&gt;It may also be hard to log such issues, especially if the request indeed runs indefinitely. In such cases, the only indication of a problem would be excessive number of active processes in PHP-FPM.&lt;/p&gt;
&lt;h1&gt;
  
  
  Timeouts
&lt;/h1&gt;

&lt;p&gt;Timeouts are a way to mitigate this problems and can be configured in several layers, and to achieve optimal results certainly should be done so. The layers we’re going to look at are server, application and database. Let’s look at what each level has to provide. I will be looking at Apache and Nginx web servers, PHP and MySQL.&lt;/p&gt;
&lt;h2&gt;
  
  
  Web server
&lt;/h2&gt;

&lt;p&gt;Web servers are the first layer where the request arrives. I tested locally with official Apache PHP docker image, and official Nginx and PHP-FPM images.&lt;/p&gt;

&lt;p&gt;The first curiosity was Apache timeouts, which didn’t appear to have any effect whatsoever. Even with &lt;a href="https://httpd.apache.org/docs/2.4/mod/core.html#timeout"&gt;&lt;code&gt;Timeout&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://httpd.apache.org/docs/2.4/mod/mod_reqtimeout.html"&gt;&lt;code&gt;RequestReadTimeout&lt;/code&gt;&lt;/a&gt; set to low values, &lt;code&gt;sleep(PHP_MAX_INT);&lt;/code&gt; would run obliviously for hours, until I finally closed the browser tab.&lt;/p&gt;

&lt;p&gt;Nginx fared better – the request was terminated when &lt;a href="http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_read_timeout"&gt;&lt;code&gt;fastcgi_read_timeout&lt;/code&gt;&lt;/a&gt; was exceeded. When there was no output at the time of termination, Nginx served a static 504 error page. I didn’t find a way to gracefully shut down the PHP application however, as there was no &lt;code&gt;SIGTERM&lt;/code&gt; signal, and shutdown function wasn’t triggered. When I increased &lt;a href="https://www.php.net/manual/en/install.fpm.configuration.php#process-control-timeout"&gt;&lt;code&gt;process_control_timeout&lt;/code&gt;&lt;/a&gt; setting in PHP-FPM, then the PHP application continued as normal, and &lt;code&gt;connection_aborted&lt;/code&gt; function didn’t report anything unusual. Therefore, I would recommend to use web server timeout as a last resort.&lt;/p&gt;
&lt;h2&gt;
  
  
  PHP
&lt;/h2&gt;

&lt;p&gt;An obvious solution to timing out the process is by setting the &lt;code&gt;max_execution_time&lt;/code&gt; value in PHP configuration. What is not so obvious is that &lt;code&gt;max_execution_time&lt;/code&gt; appears to ignore time spent on IO, such as running database queries. This is what a typical PHP application spends majority of it’s time on. Thus, it seems that it is only useful for catching problems like infinite loops. So something to think about, but not as useful as it appears.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The set_time_limit() function and the configuration directive max_execution_time only affect the execution time of the script itself. Any time spent on activity that happens outside the execution of the script such as system calls using system(), stream operations, database queries, etc. is not included when determining the maximum time that the script has been running. This is not true on Windows where the measured time is real.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Source: &lt;a href="https://www.php.net/manual/en/function.set-time-limit.php"&gt;PHP: set_time_limit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A workaround involves using &lt;code&gt;pcntl&lt;/code&gt; extension, which is not supported in many environments, such as &lt;code&gt;mod_php&lt;/code&gt; module for Apache, because the PHP application shouldn’t be fiddling with processes in server environment.&lt;/p&gt;

&lt;p&gt;The workaround seems fairly innocent, and is possible to use in PHP-FPM, so I will take a look at it anyway:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="c1"&gt;# https://stackoverflow.com/questions/7493676/detecting-a-timeout-for-a-block-of-code-in-php/7493838&lt;/span&gt;

&lt;span class="c1"&gt;# fork the process&lt;/span&gt;

&lt;span class="nv"&gt;$pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;pcntl_fork&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$pid&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;# application code&lt;/span&gt;

    &lt;span class="c1"&gt;# cleanup on SIGALRM&lt;/span&gt;
    &lt;span class="nb"&gt;pcntl_async_signals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;pcntl_signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SIGALRM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;# simulation of cleanup work&lt;/span&gt;
        &lt;span class="k"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;# simulation of long running process&lt;/span&gt;
    &lt;span class="nb"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;# timeout process&lt;/span&gt;

    &lt;span class="c1"&gt;# timing variables &lt;/span&gt;
    &lt;span class="nv"&gt;$softTimeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//s&lt;/span&gt;
    &lt;span class="nv"&gt;$hardTimeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$softTimeout&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//s&lt;/span&gt;
    &lt;span class="nv"&gt;$interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// μs&lt;/span&gt;
    &lt;span class="nv"&gt;$start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;microtime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nb"&gt;pcntl_async_signals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$signo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$hardTimeout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;posix_kill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$signo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;usleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$interval&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;pcntl_wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WNOHANG&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nx"&gt;WUNTRACED&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nb"&gt;microtime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nv"&gt;$hardTimeout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;# Immediate termination&lt;/span&gt;
                &lt;span class="nb"&gt;posix_kill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SIGKILL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nb"&gt;pcntl_wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="c1"&gt;# Termination signals&lt;/span&gt;
    &lt;span class="nb"&gt;pcntl_signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SIGTERM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;pcntl_signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SIGINT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;pcntl_signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SIGQUIT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;pcntl_signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SIGHUP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;# Alarm signal&lt;/span&gt;
    &lt;span class="nb"&gt;pcntl_signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SIGALRM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nb"&gt;register_shutdown_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;pcntl_alarm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nb"&gt;pcntl_alarm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$softTimeout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nb"&gt;pcntl_wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$pid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;p&gt;EDIT: Reflecting back on this, a simpler approach without forking is also possible with &lt;code&gt;pcntl_alarm&lt;/code&gt;, and is probably a better choice in most situations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="nv"&gt;$timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;# cleanup on SIGALRM&lt;/span&gt;
&lt;span class="nb"&gt;pcntl_async_signals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;pcntl_signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SIGALRM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"interupt"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nb"&gt;register_shutdown_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;pcntl_alarm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nb"&gt;pcntl_alarm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$timeout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nb"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;PHP_INT_MAX&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;p&gt;EDIT2: Preliminary testing with PHP-FPM shows a somewhat expected caveat with this approach, which is related to PHP-FPM reusing same processes for multiple requests. &lt;code&gt;pcntl-alarm&lt;/code&gt; will send &lt;code&gt;SIGALRM&lt;/code&gt; to the PHP-FPM worker, which may at time of triggering be doing nothing or processing another request. So at minimum, the script should do it's best to clean up the alarm in &lt;code&gt;register_shutdown_function&lt;/code&gt;. I've update the previous example accordingly.&lt;/p&gt;




&lt;p&gt;EDIT3: I'd like to see that done in PHP-FPM, and to some extent it is possible with &lt;a href="https://www.php.net/manual/en/install.fpm.configuration.php#request-terminate-timeout"&gt;&lt;code&gt;request_terminate_timeout&lt;/code&gt;&lt;/a&gt;, but AFAIK this can only be set to same value for all workers in the pool, and it kills the worker (I'd prefer trying a soft termination first and not killing the worker unless necessary).&lt;/p&gt;




&lt;p&gt;A safer approach could be to offload work using &lt;a href="http://gearman.org/"&gt;Gearman&lt;/a&gt;. With such approach PHP-FPM would only pass requests to Gearman. When designing such a solution, it is important to keep in mind that Gearman workers do not benefit from persistent database connections.&lt;/p&gt;

&lt;h2&gt;
  
  
  Database
&lt;/h2&gt;

&lt;p&gt;Communication with database is where PHP applications tend to spend most of their time. It would be only natural to establish limits to database operations.&lt;/p&gt;

&lt;p&gt;In my case, the application specified &lt;code&gt;MYSQLI_OPT_CONNECT_TIMEOUT&lt;/code&gt; using &lt;a href="https://www.php.net/manual/en/mysqli.options.php"&gt;mysqli_options&lt;/a&gt;. But why didn’t that stop the long running query? PHP documentation comment section provided a clue. Turns out that connection timeout only times out the phase where PHP establishes connection to MySQL server and it doesn’t affect the queries at all. In fact, with persistent database connections, the database connections are shared between requests, and can therefore be rather long lived. PHP has another option for limiting query execution times, &lt;code&gt;MYSQLI_OPT_READ_TIMEOUT&lt;/code&gt;, but it does not appear in the documentation. Digging in PHP source, this is first mentioned in a non-released NEWS file for PHP 7.1 RC, but the constant doesn’t seem to make appearance before PHP 7.2 RC. And many users report success in earlier PHP versions by manually declaring the constant. &lt;/p&gt;

&lt;p&gt;When testing this option, the behavior appears to be as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the query execution interval is below timeout, nothing happens.&lt;/li&gt;
&lt;li&gt;When timeout is exceeded the connection is dropped (&lt;code&gt;2006 MySQL server has gone away&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There seems to be more though. mysqlnd has an INI setting &lt;a href="https://www.php.net/manual/en/mysqlnd.config.php#ini.mysqlnd.net-read-timeout"&gt;&lt;code&gt;mysqlnd.net_read_timeout&lt;/code&gt;&lt;/a&gt;, which reads to do the same thing, but the documentation also notes &lt;code&gt;MYSQL_OPT_READ_TIMEOUT&lt;/code&gt; only works for TCP/IP connections, and prior to MySQL 5.1.2, only for Windows.&lt;/p&gt;

&lt;p&gt;Testing with mysqli revealed that both ways work identically, sockets included. However, the option can only be passed with &lt;a href="https://www.php.net/manual/en/mysqli.options.php"&gt;&lt;code&gt;mysqli_options&lt;/code&gt;&lt;/a&gt;, whereas the INI setting can be also used with PDO.&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;Control over timeouts in PHP appears rather complicated, especially when compared to asynchronous languages like Node JS, but can certainly be done right.&lt;/p&gt;

&lt;p&gt;Given the issues with timeouts and lack of pcntl support in Apache, Nginx + PHP-FPM combo seems like a more solid option.&lt;/p&gt;

&lt;p&gt;The timeout strategies in PHP need a careful thought. An architecture using Gearman certainly looks promising, and I have used it with success in the past. However, I will probably give &lt;del&gt;process forking&lt;/del&gt; &lt;code&gt;pcntl_alarm&lt;/code&gt; with PHP-FPM a try.&lt;/p&gt;

&lt;p&gt;The read timeouts in MySQL is a must combined with connect timeout to avoid available worker pool exhaustion in case of a hanging query.&lt;/p&gt;

</description>
      <category>php</category>
      <category>mysql</category>
      <category>linux</category>
    </item>
  </channel>
</rss>
