feat(pargar): prune inbound logs via MySQL INSERT trigger

Run one-time overflow cleanup on migrate and keep mande/document success
rows capped at 2000 with an AFTER INSERT trigger, without cron or manual SQL.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-03 20:24:44 +03:30
co-authored by Cursor
parent 3b7db1eb72
commit f3eaf91559
3 changed files with 126 additions and 51 deletions
@@ -0,0 +1,112 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
/**
* تریگر MySQL روی INSERT — بدون artisan/cron/SQL دستی.
* migrate یک‌بار: انباشت قدیمی mande/document را می‌بُرد + تریگر برای نگه‌داری ۲۰۰۰ تازه.
*/
return new class extends Migration
{
private const KEEP = 2000;
private const TRIGGER = 'pargar_sync_logs_prune_inbound_after_insert';
public function up(): void
{
if (! Schema::hasTable('pargar_sync_logs')) {
return;
}
$this->dropHourlyEvents();
$this->dropTrigger();
$this->pruneExistingOverflow('document');
$this->pruneExistingOverflow('mande');
$this->createInsertTrigger();
}
public function down(): void
{
$this->dropTrigger();
}
private function dropHourlyEvents(): void
{
try {
DB::unprepared('DROP EVENT IF EXISTS `khanegi_prune_pargar_inbound_docs`');
DB::unprepared('DROP EVENT IF EXISTS `khanegi_prune_pargar_inbound_mande`');
} catch (\Throwable) {
}
}
private function dropTrigger(): void
{
try {
DB::unprepared('DROP TRIGGER IF EXISTS `' . self::TRIGGER . '`');
} catch (\Throwable) {
}
}
private function pruneExistingOverflow(string $type): void
{
$keep = self::KEEP;
try {
DB::unprepared(<<<SQL
DELETE FROM `pargar_sync_logs`
WHERE `type` = '{$type}' AND `sync_status` = 'success'
AND `id` <= (
SELECT `cutoff` FROM (
SELECT `id` AS `cutoff` FROM `pargar_sync_logs`
WHERE `type` = '{$type}' AND `sync_status` = 'success'
ORDER BY `id` DESC
LIMIT 1 OFFSET {$keep}
) AS `keep`
)
SQL);
} catch (\Throwable) {
// اگر overflow نیست یا دسترسی محدود است، تریگر بعداً نگه می‌دارد
}
}
private function createInsertTrigger(): void
{
$keep = self::KEEP;
$trigger = self::TRIGGER;
DB::unprepared(<<<SQL
CREATE TRIGGER `{$trigger}`
AFTER INSERT ON `pargar_sync_logs`
FOR EACH ROW
BEGIN
IF NEW.`type` = 'document' AND NEW.`sync_status` = 'success' THEN
DELETE FROM `pargar_sync_logs`
WHERE `type` = 'document' AND `sync_status` = 'success'
AND `id` <= (
SELECT `cutoff` FROM (
SELECT `id` AS `cutoff` FROM `pargar_sync_logs`
WHERE `type` = 'document' AND `sync_status` = 'success'
ORDER BY `id` DESC
LIMIT 1 OFFSET {$keep}
) AS `keep`
)
LIMIT 4000;
ELSEIF NEW.`type` = 'mande' AND NEW.`sync_status` = 'success' THEN
DELETE FROM `pargar_sync_logs`
WHERE `type` = 'mande' AND `sync_status` = 'success'
AND `id` <= (
SELECT `cutoff` FROM (
SELECT `id` AS `cutoff` FROM `pargar_sync_logs`
WHERE `type` = 'mande' AND `sync_status` = 'success'
ORDER BY `id` DESC
LIMIT 1 OFFSET {$keep}
) AS `keep`
)
LIMIT 4000;
END IF;
END
SQL);
}
};
+2 -44
View File
@@ -41,47 +41,5 @@ WHERE `type` = 'mande' AND `sync_status` = 'success'
) AS `keep`
);
-- Event داخل خود MySQL — بدون کرون سیستم (Navicat → Events)
DROP EVENT IF EXISTS `khanegi_prune_pargar_inbound_docs`;
DROP EVENT IF EXISTS `khanegi_prune_pargar_inbound_mande`;
CREATE EVENT `khanegi_prune_pargar_inbound_docs`
ON SCHEDULE EVERY 1 HOUR
STARTS CURRENT_TIMESTAMP
ON COMPLETION PRESERVE
ENABLE
DO
DELETE FROM `pargar_sync_logs`
WHERE `type` = 'document' AND `sync_status` = 'success'
AND `id` <= (
SELECT `cutoff` FROM (
SELECT `id` AS `cutoff` FROM `pargar_sync_logs`
WHERE `type` = 'document' AND `sync_status` = 'success'
ORDER BY `id` DESC
LIMIT 1 OFFSET 2000
) AS `keep`
)
LIMIT 4000;
CREATE EVENT `khanegi_prune_pargar_inbound_mande`
ON SCHEDULE EVERY 1 HOUR
STARTS CURRENT_TIMESTAMP
ON COMPLETION PRESERVE
ENABLE
DO
DELETE FROM `pargar_sync_logs`
WHERE `type` = 'mande' AND `sync_status` = 'success'
AND `id` <= (
SELECT `cutoff` FROM (
SELECT `id` AS `cutoff` FROM `pargar_sync_logs`
WHERE `type` = 'mande' AND `sync_status` = 'success'
ORDER BY `id` DESC
LIMIT 1 OFFSET 2000
) AS `keep`
)
LIMIT 4000;
-- اگر دسترسی SUPER داری:
-- SET GLOBAL event_scheduler = ON;
-- SHOW VARIABLES LIKE 'event_scheduler';
-- SHOW EVENTS;
-- جایگزین: مایگریشن 2026_09_03_000002 (تریگر INSERT + prune یک‌بار روی migrate).
-- EVENT ساعتی دیگر لازم نیست.