+1

Execução de processos em segundo plano

criado por Bruno Kühnen Meneguello em 17/03/2007 11:44am
Assim que tivermos um processo em segundo plano, está na hora de nos comunicarmos com ele.

Visto que o processo está "desgarrado" do processo que o criou, será necessário definir um canal de troca de informações. Há algumas possibilidade para este canal, entre elas: banco de dados e arquivos. Não vou explorar o uso de bancos de dados como canal de comunicação pois o objetivo do artigo é usar uma conexão permanente a um banco de dados entre várias sessões.

O uso de arquivo para troca de dados e controle de processos é muito utilizado em sistemas de controle de versões (CVS). A técnica utilizada é bastante semelhante, podendo tornar-se mais complexa de acordo com a necessidade.

Para um exemplo básico, será feito um script que envia comandos SQL e os retorna em formato CSV com a primeira linha sendo o cabeçalho.

O controle do processo

O controle da execução do processo deve garantir a leitura dos dados e entrada, a execução do processamento e a saída do retorno.
Como nosso processo será acessado via arquivos, serão necessários três arquivos:

.exec - Será usado como sinalizador de andamento do processo, sua existência define que o processo está em andamento, sua ausência indica o oposto.
.in - Será a entrada de dados. Se houver bytes disponíveis no arquivo, significará que há dados a processar, ao final do processo, o arquivo será truncado e a ausência de bytes indicará que o processo deve aguardar.
.out - É a saída dos dados. Só possuirá dados válidos quando o arquivo .in não possuir um byte sequer.

O processo

O processo pode ser programado da seguinte maneira:

<?php
set_time_limit(7200);
ignore_user_abort(true);

fopen('./.exec','w');

$conn = mysql_connect($servidor,$usuario,$senha);
mysql_select_db($bdados);

while (file_exists('./.exec')) {
    clearstatcache();
    if (file_exists('./.in') && filesize('./.in')) {
        $out = fopen('./.out','w');
        $query = mysql_query(file_get_contents('./.in'));
        $campos = mysql_num_fields($query);
        $sep = '';
        for ($i = 0; $i < $campos; $i++) {
            fwrite($out,$sep.mysql_field_name($query,$i));
            $sep = ';';
        }
        fwrite($out,"\n");
        while ($res = mysql_fetch_row($query)) {
            for ($i = 1; $i < $campos; $i++) {
                fwrite($out,$sep.$res[$i]);
                $sep = ';';
            }
            fwrite($out,"\n");
        }
        fclose($out);
        fclose(fopen('./.in','w'));
    }
    sleep(1);
}
?>

As linhas 2 e 3 já foram explicadas anteriormente.
Na linha 5 é criado o arquivo .exec, sinalizando o início do processo.
Na linha 7 está o corpo de controle do processo, que é executado contínuamente enquanto existir o arquivo .exec. Na linha 32 é visto um artifício para poupar recursos do servidor e retomar o processo a cada 1 segundo.
Na linha 11 está um comando necessário para atualizar os dados sobre os arquivos utilizados, sem ele o processo trabalha sobre dados em buffer e não tem o comportamento esperado.
Na linha 12 é visto o processo de entrada de dados, ou seja, quando ouver bytes em .in, estes são processados.
Entre as linhas 13 e 30está o controle da execução do processo. Este consiste em ler a consulta do arquivo de entrada, executá-la e escrever a saída no arquivo .out no formato CSV.
Ao final, na linha 29 o arquivo .out é fechado e o arquivo .in é truncado, setando seu tamanho para 0, ou seja, validando os dados da saída.
E desta forma o processo continua enquanto não vencer o tempo limite do script ou o arquivo .exec ser removido.

Comentários:

Mostrando 1 - 2 de 2 comentários
Marcelo disse:
Muito bom!!!

Não sabia que tinha como executar em segundo plano em PHP, funciona simulando um pequeno ambiente Thread.
12/07/2009 12:05am (~15 anos atrás)

Muito bom o artigo, irei colocar em prática e passo o que tive de experiência
11/07/2009 6:22pm (~15 anos atrás)

Novo Comentário:

(Você pode usar tags como <b>, <i> ou <code>. URLs serão convertidas para links automaticamente.)