Volanie Configurator->createContainer() robí sleep() blokujúcou

martin.palenik
Člen | 3
+
0
-

Nasledovný minimal working example demonštruje problém, s ktorým sa potýkam. Funkcia sleep() je v kóde blokujúca, čiže všetky ostatné požiadavky musia počkať kým prejde 10 sekúnd. Po zakomentovaní uvedených dvoch riadkov, ale sleep() už blokujúca nie je, čo je to čo chcem.

mwe.php

<?php
require __DIR__ . '/vendor/autoload.php';

$configurator = App\Bootstrap::boot(); // Does not make sleep() blocking, provided debug mode is disabled.
$container = $configurator->createContainer(); // Makes sleep() blocking. Disabling debug mode and Tracy has no effect. Removing this line makes sleep() not blocking.
sleep(10);

Bootstrap.php

<?php
namespace App;
use Nette\Bootstrap\Configurator;
use Tracy\BlueScreen;

class Bootstrap
{
    public static function boot(): Configurator
    {
        $appDir = dirname(__DIR__);

        $configurator = new Configurator();
        $configurator->setDebugMode(false);
        $configurator->setTimeZone('Europe/Prague');
/*
        $logDir = $appDir . "/log";
        if (!is_dir($logDir) && !mkdir($logDir)) {
            if ($configurator->isDebugMode()) {
                $blueScreen = new BlueScreen();
                $blueScreen->render(new \Exception("Cannot create log directory at $logDir. Tracy debugger cannot log errors."));
            }
        }

        $configurator->enableTracy($appDir . "/log");*/
        $configurator->setTempDirectory($appDir . "/temp");
        $configurator->addConfig($appDir . '/config/services.neon');

        return $configurator;
    }
}

composer.json

{
  "autoload": {
    "psr-4": {
      "App\\": "app/",
      "DatabaseGateways\\": "DatabaseGateways/",
      "Parser\\": "Parser/"
    },
    "files": [
      "Controller.php",
      "Database.php",
      "DatabaseGateway.php",
      "ErrorHandler.php",
      "Scheduler.php"
    ]
  },
  "require": {
    "ext-pdo": "*",
	  "php": "^8.2.1 <8.4",
    "nette/bootstrap": "^3.2",
    "tracy/tracy": "^2.10",
    "nette/security": "^3.2",
    "nette/http": "^3.3"
  },
  "config": {
    "platform": {
	  "php": "8.2.1"
	}
  },
  "prefer-stable": true
}

Prečo Nette robí funkciu blokujúcou a ako to obísť, aby neblokovala ďalšie požiadavky?

Kamil Valenta
Člen | 820
+
+1
-

martin.palenik napsal(a):

čiže všetky ostatné požiadavky musia počkať

Jsi si jist, že všechny ostatní? Nebo jen „tvoje ostatní“? Myslím, že jiný client, v jiném vlákně php, čekat nebude…

Prečo Nette robí funkciu blokujúcou a ako to obísť, aby neblokovala ďalšie požiadavky?

Nestartuješ v requestech sessionu?

martin.palenik
Člen | 3
+
0
-

Nestartuješ v requestech sessionu?

Neviem, ako to zistím? Problém spôsobuje už priložený mwe.php.

Jsi si jist, že všechny ostatní? Nebo jen „tvoje ostatní“? Myslím, že jiný client, v jiném vlákně php, čekat nebude…

Musia čakať všetci, ktorí sú prihlásení v danom prehliadači v rôznych taboch. Ak sa súčasne prihlásim aj inde, napríklad do Firefoxu, tak tam čakať spravidla nemusím, ale po istom čase aj ten začína blokovať. Ale len kým bežá sleep() a hneď ako dobehne tak sa požiadavky dokončia.

Na WEDOS je obmedzenie na 30 procesov, ktoré môžu bežať zároveň, a z podpory mi písali, že sme to prekročili. Či to ale súviselo práve s týmto, to si nie som istý.

Editoval martin.palenik (30. 7. 15:31)

nightfish
Člen | 518
+
+2
-

martin.palenik napsal(a):
Musia čakať všetci, ktorí sú prihlásení v danom prehliadači v rôznych taboch.
Ak sa súčasne prihlásim aj inde, napríklad do Firefoxu, tak tam čakať spravidla nemusím, ale po istom čase aj ten začína blokovať.

@martinpalenik
To mi vskutku zní jako problém zamykání sessions. Viz třeba https://forum.nette.org/…ich-requestu

Kamil Valenta
Člen | 820
+
+2
-

Requesty, které sahají do sessiony (což pro přihlášené uživatele určitě děláš) se nevykonají asynchronně, to nemá společného nic s Nette. U sessiony se vytvoří zámek a dokud se neuvolní (např. doběhnutím skriptu), ostatní čekají v řadě. Řešením může být: neotvírat sessionu, dokud to skutečně není nevyhnutelně potřeba. Zavřít sessionu ihned, jakmile už potřeba není. Nebo handler na jinou storage.
Když budeš googlit session blocking, určitě najdeš mnoho příkladů a plusy i mínusy jednotlivých variant.

martin.palenik
Člen | 3
+
0
-

Mali ste pravdu, bol to problém session lockingu. Riešením bolo predtým zavolať session_write_close(). Napriek tomu, toto riešenie nefunguje v debug móde.

$configurator = new Configurator();
$configurator->setDebugMode(true);

Neviete prečo?

Tu je kód pre ilustráciu:

require __DIR__ . '/vendor/autoload.php';

$configurator = App\Bootstrap::boot(); // Does not make sleep() blocking, provided debug mode is disabled.

file_put_contents(__DIR__ . '/container.log', "Before createContainer: " . session_status() . "\n");                    // Before createContainer: 1
$container = $configurator->createContainer(); // Makes sleep() blocking. Disabling debug mode and Tracy has no effect. Removing this line makes sleep() not blocking.
file_put_contents(__DIR__ . '/container.log', "After createContainer: "  . session_status() . "\n", FILE_APPEND); // After createContainer: 2

if (session_status() === PHP_SESSION_ACTIVE) {
    session_write_close();
}

sleep(10);

// Reopen the session if necessary
if (session_status() !== PHP_SESSION_ACTIVE) {
    file_put_contents(__DIR__ . '/container.log', "Starting new session" . "\n", FILE_APPEND);
    file_put_contents(__DIR__ . '/container.log', "Starting new session - session_status() before: " . session_status() . "\n", FILE_APPEND); // Starting new session - session_status() before: 1
    session_start();
    file_put_contents(__DIR__ . '/container.log', "Starting new session - session_status() after: " . session_status() . "\n", FILE_APPEND); // Starting new session - session_status() after: 2
}

Editoval martin.palenik (5. 9. 9:26)