nextcloud / docker

⛴ Docker image of Nextcloud
https://hub.docker.com/_/nextcloud/
GNU Affero General Public License v3.0
5.8k stars 1.8k forks source link

fix(entrypoint): Delay on auto-install to avoid error before retry #2222

Open joshtrichards opened 1 month ago

joshtrichards commented 1 month ago

The start-up of new MariaDB/MySQL container + creation of the initial user specified via the MYSQL_* variables can take about ~4-6s even in a relatively capable/fast environment:

MariaDB container startup log with timestamps ``` test-nc29-dbpass-db-1 | 2024-05-22 21:54:33+00:00 [Note] [Entrypoint]: Entrypoint script for MariaDB Server 1:10.6.17+maria~ubu2004 started. [...] test-nc29-dbpass-db-1 | 2024-05-22 21:54:39 0 [Note] mariadbd: ready for connections. ```

When attempting a fully automated Nextcloud installation (i.e. populating a NEXTCLOUD_* variables in Compose), this can trigger a failure of the install attempt the first time around. This generates a scary looking error before we retry 10 seconds later:

Scary stack trace if database container happens to not be fully initialized yet ``` test-nc29-dbpass-app-1 | Starting nextcloud installation test-nc29-dbpass-app-1 | Error while trying to create admin account: An exception occurred in the driver: SQLSTATE[HY000] [1045] Access denied for user 'ncuser'@'localhost' (using password: YES) test-nc29-dbpass-app-1 | Trace: #0 /var/www/html/3rdparty/doctrine/dbal/src/Connection.php(1943): Doctrine\DBAL\Driver\API\MySQL\ExceptionConverter->convert(Object(Doctrine\DBAL\Driver\PDO\Exception), NULL) test-nc29-dbpass-app-1 | #1 /var/www/html/3rdparty/doctrine/dbal/src/Connection.php(1891): Doctrine\DBAL\Connection->handleDriverException(Object(Doctrine\DBAL\Driver\PDO\Exception), NULL) test-nc29-dbpass-app-1 | #2 /var/www/html/3rdparty/doctrine/dbal/src/Connections/PrimaryReadReplicaConnection.php(257): Doctrine\DBAL\Connection->convertException(Object(Doctrine\DBAL\Driver\PDO\Exception)) test-nc29-dbpass-app-1 | #3 /var/www/html/3rdparty/doctrine/dbal/src/Connections/PrimaryReadReplicaConnection.php(192): Doctrine\DBAL\Connections\PrimaryReadReplicaConnection->connectTo('primary') test-nc29-dbpass-app-1 | #4 /var/www/html/3rdparty/doctrine/dbal/src/Connections/PrimaryReadReplicaConnection.php(224): Doctrine\DBAL\Connections\PrimaryReadReplicaConnection->performConnect('primary') test-nc29-dbpass-app-1 | #5 /var/www/html/lib/private/Setup/AbstractDatabase.php(147): Doctrine\DBAL\Connections\PrimaryReadReplicaConnection->ensureConnectedToPrimary() test-nc29-dbpass-app-1 | #6 /var/www/html/lib/private/Setup/MySQL.php(43): OC\Setup\AbstractDatabase->connect(Array) test-nc29-dbpass-app-1 | #7 /var/www/html/lib/private/Setup.php(339): OC\Setup\MySQL->setupDatabase('ncadmin') test-nc29-dbpass-app-1 | #8 /var/www/html/core/Command/Maintenance/Install.php(104): OC\Setup->install(Array, NULL) test-nc29-dbpass-app-1 | #9 /var/www/html/3rdparty/symfony/console/Command/Command.php(298): OC\Core\Command\Maintenance\Install->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) test-nc29-dbpass-app-1 | #10 /var/www/html/3rdparty/symfony/console/Application.php(1040): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) test-nc29-dbpass-app-1 | #11 /var/www/html/3rdparty/symfony/console/Application.php(301): Symfony\Component\Console\Application->doRunCommand(Object(OC\Core\Command\Maintenance\Install), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) test-nc29-dbpass-app-1 | #12 /var/www/html/3rdparty/symfony/console/Application.php(171): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) test-nc29-dbpass-app-1 | #13 /var/www/html/lib/private/Console/Application.php(213): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) test-nc29-dbpass-app-1 | #14 /var/www/html/console.php(113): OC\Console\Application->run() test-nc29-dbpass-app-1 | #15 /var/www/html/occ(11): require_once('/var/www/html/c...') test-nc29-dbpass-app-1 | #16 {main} test-nc29-dbpass-app-1 | test-nc29-dbpass-app-1 | Previous: Doctrine\DBAL\Driver\PDO\Exception: SQLSTATE[HY000] [1045] Access denied for user 'ncuser'@'localhost' (using password: YES) test-nc29-dbpass-app-1 | Trace: #0 /var/www/html/3rdparty/doctrine/dbal/src/Driver/PDO/MySQL/Driver.php(40): Doctrine\DBAL\Driver\PDO\Exception::new(Object(PDOException)) test-nc29-dbpass-app-1 | #1 /var/www/html/3rdparty/doctrine/dbal/src/Connections/PrimaryReadReplicaConnection.php(255): Doctrine\DBAL\Driver\PDO\MySQL\Driver->connect(Object(SensitiveParameterValue)) test-nc29-dbpass-app-1 | #2 /var/www/html/3rdparty/doctrine/dbal/src/Connections/PrimaryReadReplicaConnection.php(192): Doctrine\DBAL\Connections\PrimaryReadReplicaConnection->connectTo('primary') test-nc29-dbpass-app-1 | #3 /var/www/html/3rdparty/doctrine/dbal/src/Connections/PrimaryReadReplicaConnection.php(224): Doctrine\DBAL\Connections\PrimaryReadReplicaConnection->performConnect('primary') test-nc29-dbpass-app-1 | #4 /var/www/html/lib/private/Setup/AbstractDatabase.php(147): Doctrine\DBAL\Connections\PrimaryReadReplicaConnection->ensureConnectedToPrimary() test-nc29-dbpass-app-1 | #5 /var/www/html/lib/private/Setup/MySQL.php(43): OC\Setup\AbstractDatabase->connect(Array) test-nc29-dbpass-app-1 | #6 /var/www/html/lib/private/Setup.php(339): OC\Setup\MySQL->setupDatabase('ncadmin') test-nc29-dbpass-app-1 | #7 /var/www/html/core/Command/Maintenance/Install.php(104): OC\Setup->install(Array, NULL) test-nc29-dbpass-app-1 | #8 /var/www/html/3rdparty/symfony/console/Command/Command.php(298): OC\Core\Command\Maintenance\Install->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) test-nc29-dbpass-app-1 | #9 /var/www/html/3rdparty/symfony/console/Application.php(1040): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) test-nc29-dbpass-app-1 | #10 /var/www/html/3rdparty/symfony/console/Application.php(301): Symfony\Component\Console\Application->doRunCommand(Object(OC\Core\Command\Maintenance\Install), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) test-nc29-dbpass-app-1 | #11 /var/www/html/3rdparty/symfony/console/Application.php(171): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) test-nc29-dbpass-app-1 | #12 /var/www/html/lib/private/Console/Application.php(213): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) test-nc29-dbpass-app-1 | #13 /var/www/html/console.php(113): OC\Console\Application->run() test-nc29-dbpass-app-1 | #14 /var/www/html/occ(11): require_once('/var/www/html/c...') test-nc29-dbpass-app-1 | #15 {main} test-nc29-dbpass-app-1 | test-nc29-dbpass-app-1 | Previous: PDOException: SQLSTATE[HY000] [1045] Access denied for user 'ncuser'@'localhost' (using password: YES) test-nc29-dbpass-app-1 | Trace: #0 /var/www/html/3rdparty/doctrine/dbal/src/Driver/PDO/MySQL/Driver.php(33): PDO->__construct('mysql:host=loca...', 'ncuser', Object(SensitiveParameterValue), Array) test-nc29-dbpass-app-1 | #1 /var/www/html/3rdparty/doctrine/dbal/src/Connections/PrimaryReadReplicaConnection.php(255): Doctrine\DBAL\Driver\PDO\MySQL\Driver->connect(Object(SensitiveParameterValue)) test-nc29-dbpass-app-1 | #2 /var/www/html/3rdparty/doctrine/dbal/src/Connections/PrimaryReadReplicaConnection.php(192): Doctrine\DBAL\Connections\PrimaryReadReplicaConnection->connectTo('primary') test-nc29-dbpass-app-1 | #3 /var/www/html/3rdparty/doctrine/dbal/src/Connections/PrimaryReadReplicaConnection.php(224): Doctrine\DBAL\Connections\PrimaryReadReplicaConnection->performConnect('primary') test-nc29-dbpass-app-1 | #4 /var/www/html/lib/private/Setup/AbstractDatabase.php(147): Doctrine\DBAL\Connections\PrimaryReadReplicaConnection->ensureConnectedToPrimary() test-nc29-dbpass-app-1 | #5 /var/www/html/lib/private/Setup/MySQL.php(43): OC\Setup\AbstractDatabase->connect(Array) test-nc29-dbpass-app-1 | #6 /var/www/html/lib/private/Setup.php(339): OC\Setup\MySQL->setupDatabase('ncadmin') test-nc29-dbpass-app-1 | #7 /var/www/html/core/Command/Maintenance/Install.php(104): OC\Setup->install(Array, NULL) test-nc29-dbpass-app-1 | #8 /var/www/html/3rdparty/symfony/console/Command/Command.php(298): OC\Core\Command\Maintenance\Install->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) test-nc29-dbpass-app-1 | #9 /var/www/html/3rdparty/symfony/console/Application.php(1040): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) test-nc29-dbpass-app-1 | #10 /var/www/html/3rdparty/symfony/console/Application.php(301): Symfony\Component\Console\Application->doRunCommand(Object(OC\Core\Command\Maintenance\Install), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) test-nc29-dbpass-app-1 | #11 /var/www/html/3rdparty/symfony/console/Application.php(171): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) test-nc29-dbpass-app-1 | #12 /var/www/html/lib/private/Console/Application.php(213): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) test-nc29-dbpass-app-1 | #13 /var/www/html/console.php(113): OC\Console\Application->run() test-nc29-dbpass-app-1 | #14 /var/www/html/occ(11): require_once('/var/www/html/c...') test-nc29-dbpass-app-1 | #15 {main} test-nc29-dbpass-app-1 | Retrying install... test-nc29-dbpass-app-1 | Nextcloud was successfully installed ```

Yes, we retry it 10s later and it all works out, but we can avoid this entirely by doing the delay before we even hit the retry cycle.

This PR:

pierreozoux commented 1 month ago

I get the idea ( I contribute rarely here, so maybe don't take into account my comment), but usually adding a sleep somewhere is not the best idea.

So I think, what you try to avoid is the scary error.

Then, why not hiding it? I did a suggestion, that might work to hide it ( I didn't tested ).

Hope it helps :)

J0WI commented 4 weeks ago

I'm not fully convinced to just add a random sleep before every step. This might be useful for some cases, but slows it down for those cases where you connect it to a database service that is already running.

You can speed-up MariaDB initialisation with MARIADB_INITDB_SKIP_TZINFO.