DbCheck.php 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Service\Cron\Job;
  4. use App\Service\Cron\BaseCronJob;
  5. use Doctrine\DBAL\Connection;
  6. use Doctrine\ORM\EntityManagerInterface;
  7. /**
  8. * Cron job dédié au contrôle du backup de la DB Opentalent.
  9. * Ce backup est remonté chaque nuit sur l'env. 'test9'.
  10. *
  11. * Ce script permet de vérifier l'intégrité du dump,
  12. * en vérifiant que toutes les tables ont bien été restaurées, et
  13. * que les tables contiennent toutes des données (hors tables ignorées)
  14. *
  15. * Pour exécuter :
  16. *
  17. * >>> bin/console ot:cron run db-check
  18. */
  19. class DbCheck extends BaseCronJob
  20. {
  21. public const IGNORE_EMPTY_TABLES = [
  22. 'messenger_messages',
  23. 'enqueue',
  24. 'zzz_.*',
  25. 'CycleByEducation', // Table a priori non utilisée
  26. 'educationalproject_file',
  27. 'ElasticaSynchro',
  28. 'Odyssee',
  29. 'PeriodNotation', // Table a priori non utilisée
  30. 'Presence',
  31. 'tag_accessWish',
  32. 'tag_control',
  33. 'tag_educationNotation',
  34. 'tag_educationStudent',
  35. 'tag_repair',
  36. ];
  37. public function __construct(
  38. private readonly EntityManagerInterface $testBackupEntityManager,
  39. ) {
  40. parent::__construct();
  41. }
  42. public function preview(): void
  43. {
  44. $this->ui->print('No preview available for this job');
  45. }
  46. /**
  47. * Execute database integrity checks.
  48. */
  49. public function execute(): void
  50. {
  51. $this->logger->info('Démarrage de la vérification de l\'intégrité de la base de données');
  52. $this->logger->info('1. Vérification de la connexion à la base de données');
  53. try {
  54. $connection = $this->getDbConnection();
  55. } catch (\Exception $e) {
  56. $this->logger->critical($e->getMessage());
  57. return;
  58. }
  59. $this->logger->info('2. Vérification de l\'intégrité des données');
  60. try {
  61. $schemaManager = $connection->createSchemaManager();
  62. $tables = $schemaManager->listTableNames();
  63. $this->logger->debug(sprintf('Nombre total de tables: %d', count($tables)));
  64. $emptyTables = [];
  65. foreach ($tables as $table) {
  66. try {
  67. if (preg_match('/^'.implode('|', self::IGNORE_EMPTY_TABLES).'$/', $table)) {
  68. $this->logger->debug(sprintf('Table %s: -- ignored --', $table));
  69. continue;
  70. }
  71. $count = (int) $connection->executeQuery("SELECT COUNT(*) FROM {$table}")->fetchOne();
  72. if (!$count > 0) {
  73. $emptyTables[] = $table;
  74. }
  75. $this->logger->debug(sprintf('Table %s: %d enregistrements', $table, $count));
  76. } catch (\Exception $tableException) {
  77. $this->logger->critical(sprintf('Impossible de vérifier la table %s: %s', $table, $tableException->getMessage()));
  78. }
  79. }
  80. if (count($emptyTables) > 0) {
  81. $this->logger->critical('%d tables vides détectées sur %d tables au total');
  82. $this->logger->error('Tables vides:');
  83. foreach ($emptyTables as $table) {
  84. $this->logger->error('- '.$table);
  85. }
  86. } else {
  87. $this->logger->info('Toutes les tables sont présentes et contiennent des données');
  88. }
  89. } catch (\Exception $e) {
  90. $this->logger->critical('Erreur lors de la vérification de l\'intégrité des données: '.$e->getMessage());
  91. $this->logger->debug('Stack trace: '.$e->getTraceAsString());
  92. }
  93. }
  94. /**
  95. * Establishes a connection to the database.
  96. *
  97. * @return Connection the active database connection
  98. *
  99. * @throws \RuntimeException if the connection could not be established
  100. * or if an error occurs during the process
  101. */
  102. private function getDbConnection(): Connection
  103. {
  104. try {
  105. /** @var Connection $connection */
  106. $connection = $this->testBackupEntityManager->getConnection();
  107. $connection->connect();
  108. if ($connection->isConnected()) {
  109. $this->logger->info('Connexion à la base de données testBackup établie avec succès');
  110. $params = $connection->getParams();
  111. $this->logger->debug(sprintf(
  112. 'Paramètres de connexion testBackup: Driver=%s, Host=%s, Port=%s, Database=%s, User=%s',
  113. $params['driver'] ?? 'N/A',
  114. $params['host'] ?? 'N/A',
  115. $params['port'] ?? 'N/A',
  116. $params['dbname'] ?? 'N/A',
  117. $params['user'] ?? 'N/A'
  118. ));
  119. } else {
  120. throw new \RuntimeException('Impossible de se connecter à la base de données');
  121. }
  122. } catch (\Exception $e) {
  123. throw new \RuntimeException('Erreur lors de la connexion à la base de données: '.$e->getMessage());
  124. }
  125. return $connection;
  126. }
  127. }