Bläddra i källkod

[PHP-FPM] Use php script instead of sql event to clean sasl_log table

FreddleSpl0it 1 år sedan
förälder
incheckning
b54a9c7bb3
3 ändrade filer med 113 tillägg och 19 borttagningar
  1. 0 17
      data/Dockerfiles/phpfpm/docker-entrypoint.sh
  2. 106 0
      data/cron/phpfpm/clear_sasl_log.php
  3. 7 2
      docker-compose.yml

+ 0 - 17
data/Dockerfiles/phpfpm/docker-entrypoint.sh

@@ -174,23 +174,6 @@ END;
 //
 DELIMITER ;
 DROP EVENT IF EXISTS clean_sasl_log;
-DELIMITER //
-CREATE EVENT clean_sasl_log
-ON SCHEDULE EVERY 1 DAY DO
-BEGIN
-  DELETE sasl_log.* FROM sasl_log
-    LEFT JOIN (
-      SELECT username, service, MAX(datetime) AS lastdate
-      FROM sasl_log
-      GROUP BY username, service
-    ) AS last ON sasl_log.username = last.username AND sasl_log.service = last.service
-    WHERE datetime < DATE_SUB(NOW(), INTERVAL 31 DAY) AND datetime < lastdate;
-  DELETE FROM sasl_log
-    WHERE username NOT IN (SELECT username FROM mailbox) AND
-    datetime < DATE_SUB(NOW(), INTERVAL 31 DAY);
-END;
-//
-DELIMITER ;
 EOF
 fi
 

+ 106 - 0
data/cron/phpfpm/clear_sasl_log.php

@@ -0,0 +1,106 @@
+<?php
+require_once "/web/inc/vars.inc.php";
+if (file_exists('/web/inc/vars.local.inc.php')) {
+  include_once('/web/inc/vars.local.inc.php');
+}
+ini_set('error_reporting', 0);
+// Init database
+//$dsn = $database_type . ':host=' . $database_host . ';dbname=' . $database_name;
+$dsn = $database_type . ":unix_socket=" . $database_sock . ";dbname=" . $database_name;
+$opt = [
+  PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
+  PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
+  PDO::ATTR_EMULATE_PREPARES   => false,
+];
+try {
+  $pdo = new PDO($dsn, $database_user, $database_pass, $opt);
+}
+catch (PDOException $e) {
+  echo($e->getMessage() . PHP_EOL);
+  exit;
+}
+
+
+try {
+  $dateThreshold = new DateTime();
+  $dateThreshold->modify('-31 days');
+  $dateThresholdFormatted = $dateThreshold->format('Y-m-d H:i:s');
+
+  $batchSize = 1000;
+  $lastProcessedDatetime = null;
+  $lastFetchedRows = 0;
+  $loopCounter = 0;
+  $rowCounter = 0;
+  $clearedRowCounter = 0;
+
+  do {
+    $loopCounter++;
+    echo("Processing batch $loopCounter\n");
+
+    $stmt = $pdo->prepare("
+      SELECT service, real_rip, username, datetime
+      FROM sasl_log
+      WHERE datetime < :dateThreshold
+      AND (:lastProcessedDatetime IS NULL OR datetime >= :lastProcessedDatetime2)
+      ORDER BY datetime ASC
+      LIMIT :limit
+    ");
+    $stmt->execute(array(
+      ':dateThreshold' => $dateThresholdFormatted,
+      ':lastProcessedDatetime' => $lastProcessedDatetime,
+      ':lastProcessedDatetime2' => $lastProcessedDatetime,
+      ':limit' => $batchSize
+    ));
+
+    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+    $rowCount = count($rows);
+    $rowCounter += $rowCount;
+
+    echo("Fetched $rowCount rows (total of $rowCounter)\n");
+
+    foreach ($rows as $row) {
+      $stmt = $pdo->prepare("
+        SELECT MAX(datetime) as max_date
+        FROM sasl_log
+        WHERE datetime < :dateThreshold AND service = :service AND username = :username
+      ");
+      $stmt->execute(array(
+        ':dateThreshold' => $dateThresholdFormatted,
+        ':service' => $row['service'],
+        ':username' => $row['username']
+      ));
+      $subrow = $stmt->fetch(PDO::FETCH_ASSOC);
+
+      if ($row['datetime'] < $subrow['max_date']) {
+        $stmt = $pdo->prepare("
+          DELETE FROM sasl_log
+          WHERE username = :username AND service = :service AND datetime = :datetime
+        ");
+        $stmt->execute(array(
+          ':username' => $row['username'],
+          ':service' => $row['service'],
+          ':datetime' => $row['datetime']
+        ));
+
+        $clearedRowCounter++;
+      }
+    }
+
+    if ($lastFetchedRows == $rowCount && $rowCount != $batchSize) {
+      $rowCount = 0;
+    }
+
+    // Update last processed datetime
+    if ($rowCount > 0) {
+      $lastProcessedDatetime = $rows[$rowCount - 1]['datetime'];
+      $lastFetchedRows = $rowCount;
+    }
+
+  } while ($rowCount > 0);
+}
+catch (PDOException $e) {
+  echo($e->getMessage() . PHP_EOL);
+  exit;
+}
+
+echo("Succesfully cleared $clearedRowCounter rows of $rowCounter rows");

+ 7 - 2
docker-compose.yml

@@ -111,13 +111,14 @@ services:
             - rspamd
 
     php-fpm-mailcow:
-      image: mailcow/phpfpm:1.89
+      image: mailcow/phpfpm:1.90
       command: "php-fpm -d date.timezone=${TZ} -d expose_php=0"
       depends_on:
         - redis-mailcow
       volumes:
         - ./data/hooks/phpfpm:/hooks:Z
         - ./data/web:/web:z
+        - ./data/cron/phpfpm:/cron:z
         - ./data/conf/rspamd/dynmaps:/dynmaps:ro,z
         - ./data/conf/rspamd/custom/:/rspamd_custom_maps:z
         - rspamd-vol-1:/var/lib/rspamd
@@ -169,6 +170,10 @@ services:
         - WEBAUTHN_ONLY_TRUSTED_VENDORS=${WEBAUTHN_ONLY_TRUSTED_VENDORS:-n}
         - CLUSTERMODE=${CLUSTERMODE:-}
         - FLATCURVE_EXPERIMENTAL=${FLATCURVE_EXPERIMENTAL:-}
+      labels:
+        ofelia.enabled: "true"
+        ofelia.job-exec.php_clear_sasl_log.schedule: "@every 1d"
+        ofelia.job-exec.php_clear_sasl_log.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && php /cron/clear_sasl_log.php || exit 0\""
       restart: always
       networks:
         mailcow-network:
@@ -552,7 +557,7 @@ services:
           aliases:
             - dockerapi
 
-    
+
     ##### Will be removed soon #####
     solr-mailcow:
       image: mailcow/solr:1.8.3