phpwaitsleepusleep

How to slow down only the current request? sleep() doesn't work as expected


Sometimes my application needs to wait for something. For example, in case of caching: if an object is not found in the cache, then the script sets a special value under its key, symbolizing the fact that its value is currently being calculated, and upon completion it writes it. If at the moment of calculation another client requests the same object, then the script will not recalculate it, but will simply wait for the first one. This is a simplified explanation, of course. I don't know how to do that correctly, but this behavior seems to me to be very logical.

In the process of testing a completely different thing, today I ran into a problem.

<?php
echo time() . "\n";
sleep(10); // usleep() has the same effect
echo time() . "\n";

At the same second, I open this page in a browser in two tabs and expect to see the same numbers, but… The tab that was opened later, in addition to its delay, for some reason, is waiting for the first tab delay (lame wording, but you understand me), so I see something like this: 1615749037 1615749047, 1615749047 1615749057. If you add more tabs, then each next one will wait for all the previous ones.

It broke my brain. This is not how I imagined it at all and was in this delusion for many years. I have not been able to find any information on this right now. First of all, I'm interested in how to achieve the desired result. Why sleep() behaves this way, I seem to be starting to guess, but I'll be glad if you share some information. Thank you!

UPD. Just in case, I checked this: if I add header('Cache-Control: no-cache, no-store, must-revalidate'), then nothing changes for me. But if I open tabs from different browsers, then there's no problem.


Solution

  • From reading I see two questions

    1. How do I block a second request, while processing the first one?

    For that my answer would be locks. For PHP specifically I'd recommend the Symfony lock component. You'll make both requests acquire a lock and only release it after you're done and the cache is generated.

    2. Why do 2 requests fired at the same time wait for each other?

    My guess here is that your browser has some built-in queuing/caching or whatnot. You can circumvent this by opening the same page in different browsers to see if that yields different results.