Gerenciamento de Exclusão Automática de Arquivos com ThinkPHP 6 e Redis

A automação da limpeza de arquivos temporários é uma tarefa comum em sistemas de backend. Uma abordagem eficiente para resolver esse problema no framework ThinkPHP 6 é utilizar o sistema de notificações de expiração de chaves do Redis (Keyspace Notifications). Este método permite disparar uma ação de exclusão no sistema de arquivos assim que uma chave específica expira no banco de dados em memória.

1. Criação do Comando Personalizado

Para manter um procesos ouvindo os eventos do Redis de forma contínua, devemos criar um comando de console no ThinkPHP. Execute o seguinte comando no terminal:

php think make:command FileCleanup

Edite o arquivo gerado em app/command/FileCleanup.php com a lógica para monitorar a expiração:

<?php
declare (strict_types = 1);

namespace app\command;

use think\console\Command;
use think\console\Input;
use think\console\Output;

class FileCleanup extends Command
{
    protected function configure()
    {
        $this->setName('storage:clean')
             ->setDescription('Monitora e remove arquivos baseados na expiração do Redis');
    }

    protected function execute(Input $input, Output $output)
    {
        $redisHost = '127.0.0.1';
        $redisPort = 6379;

        $client = new \Redis();
        $client->connect($redisHost, $redisPort);
        
        // Habilita notificações de expiração de chaves (Ex)
        $client->setOption(\Redis::OPT_READ_TIMEOUT, -1);
        $client->config('SET', 'notify-keyspace-events', 'Ex');

        $output->writeln("Ouvindo eventos de expiração no Redis...");

        // Inscreve-se no canal de eventos de expiração do banco de dados 0
        $client->psubscribe(['__keyevent@0__:expired'], function ($instance, $pattern, $channel, $fileName) use ($output) {
            $basePath = app()->getRootPath() . "public/static/uploads/";
            $fullPath = $basePath . $fileName;

            if (file_exists($fullPath)) {
                if (unlink($fullPath)) {
                    $output->writeln("Arquivo removido com sucesso: " . $fileName);
                } else {
                    $output->writeln("Falha ao remover o arquivo: " . $fileName);
                }
            }
        });
    }
}

2. Registro do Comando

Registre o novo comando no arquivo de configruação de console localizado em config/console.php:

<?php
return [
    'commands' => [
        'storage:clean' => 'app\command\FileCleanup',
    ]
];

3. Configuração do Servidor

Para que o sistema funcione corretamente, certifique-se de que o ambiente atenda aos seguintes requisitos:

  • Redis Server instalado e em execução.
  • Extensão php-redis instalada e habilitada na versão do PHP utilizada pelo CLI.
  • O parâmetro notify-keyspace-events deve estar configurado como Ex no arquivo redis.conf ou via comando.

4. Testando a Implementação

No seu controlador, você pode definir uma chave no Redis cujo nome corresponda ao nome do arquivo que deseja remover após um período determinado:

<?php
namespace app\controller;

use app\BaseController;
use think\facade\Cache;

class AssetManager extends BaseController
{
    public function scheduleDeletion()
    {
        $fileName = "temp_report.pdf";
        $ttl = 60; // Tempo de vida em segundos

        $redis = new \Redis();
        $redis->connect('127.0.0.1', 6379);
        
        // Define a chave com valor arbitrário e tempo de expiração
        $redis->setex($fileName, $ttl, "pending_deletion");

        return json(['msg' => "Remoção de {$fileName} agendada para daqui a {$ttl} segundos."]);
    }
}

Inicie o worker manualmente para testes:

php think storage:clean

5. Persistência com Supervisor

Em ambiente de produção, o comando deve ser executado como um processo de segundo plano persistente. O uso do Supervisor é recomendado para garantir que o comando reinicie automaticamente em caso de falha.

Exemplo de configuração do Supervisor:

[program:tp6-redis-cleaner]
command=php /caminho/do/projeto/think storage:clean
directory=/caminho/do/projeto
autostart=true
autorestart=true
user=www
stderr_logfile=/var/log/redis-cleaner.err.log
stdout_logfile=/var/log/redis-cleaner.out.log

Tags: ThinkPHP 6 Redis PHP backend Redis Keyspace Notifications

Publicado em 9-22 14:36