Manager: Perform module loading asynchronously

So that authentication can suspend it. There are cases,
e.g. cube, where authentication is required in run.php.
During bootstrapping loading modules is mostly required
to load libraries, register routes and hooks. Most of the
time authentication is not required for these, but if
it is, evaluation is now interrupted and continued
after authentication has actually been performed.

I don't see a real risk for any breaking change here,
since authentication happens shortly after. It actually
avoids a breaking change, since without this, cube's
Icinga DB support would break or at least malfunction.

And cube is only a single example.

refs #5265
This commit is contained in:
Johannes Meyer 2025-07-08 14:30:16 +02:00
parent 4ebd1e42e0
commit 078fdc84ab
2 changed files with 34 additions and 2 deletions

View File

@ -3,6 +3,7 @@
namespace Icinga\Application\Modules;
use Fiber;
use Icinga\Application\ApplicationBootstrap;
use Icinga\Application\Icinga;
use Icinga\Application\Logger;
@ -187,8 +188,16 @@ class Manager
public function loadEnabledModules()
{
if (! $this->loadedAllEnabledModules) {
$async = ! $this->app->isCli();
foreach ($this->listEnabledModules() as $name) {
if ($async) {
// May be suspended during authentication and resumed upon finish
(new Fiber(function () use ($name) {
$this->loadModule($name);
}))->start();
} else {
$this->loadModule($name);
}
}
$this->loadedAllEnabledModules = true;

View File

@ -4,6 +4,7 @@
namespace Icinga\Authentication;
use Exception;
use Fiber;
use Icinga\Application\Config;
use Icinga\Application\Hook\AuditHook;
use Icinga\Application\Icinga;
@ -59,6 +60,15 @@ class Auth
*/
private bool $authenticated = false;
/**
* Fibers that were suspended during authentication
*
* This is used to resume fibers after authentication has been performed.
*
* @var Fiber[]
*/
private array $suspendedFibers = [];
/**
* @see getInstance()
*/
@ -97,8 +107,14 @@ class Auth
public function isAuthenticated()
{
if (! $this->authenticated) {
$fiber = Fiber::getCurrent();
if ($fiber !== null) {
$this->suspendedFibers[] = $fiber;
Fiber::suspend();
} else {
trigger_error('Authentication can no longer be triggered implicitly', E_USER_DEPRECATED);
}
}
return $this->user !== null;
}
@ -250,6 +266,13 @@ class Auth
$this->authenticated = true;
foreach ($this->suspendedFibers as $fiber) {
// Resume all suspended fibers
$fiber->resume();
}
$this->suspendedFibers = [];
return $this;
}