Servidor HTTP Apache - Como determinar no servidor se um download foi concluído e de qual arquivo?

3

Temos um servidor Apache HTTP instalado e em execução, que serve arquivos zip dinamicamente criados para os usuários, possivelmente com vários 100s de megabytes de tamanho. À medida que criamos um novo arquivo a cada clique no botão "download" (mesmo que o conteúdo não tenha mudado ...), provavelmente teremos problemas de capacidade de disco.

Eu tenho um script bastante burro que exclui todos os arquivos que foram criados há 90 + minutos. Obviamente, não é legal essa solução.

Eu queria saber como determinar a partir da linha de comando do servidor quando um download foi concluído, com sucesso ou não. Nesse caso, posso excluir esse arquivo, pois ele não será exibido duas vezes. Pensando nisso, pode até ser suficiente verificar se o servidor está usando um arquivo ou não, pois ele é criado antes de ser exibido ao cliente.

Obrigado!

    
por Wolfram 03.07.2009 / 18:45

7 respostas

10

Desde excluir um arquivo que um processo tem um identificador de arquivo aberto em deixa o arquivo lá até que o identificador seja fechado você poderia simplesmente excluí-los imediatamente, e quando o Apache fechar o arquivo, ele será removido do disco.

    
por 03.07.2009 / 19:00
3

TRS-80 tem a idéia certa, e eu definitivamente recomendo seguir esse caminho. Se você estiver pronto para esperar até que a transferência termine, considere usar lsof para determinar quando ninguém abriu o arquivo. Então, algo como:

for file in /directory/full/of/zips/*.zip; do
  if [ -z "$(lsof $file)" ]; then
    # Nobody's reading it, delete
    rm $file
  fi
done
    
por 04.07.2009 / 01:11
1

A primeira maneira que vejo é analisar o resultado do status do servidor para saber se o download foi iniciado. Quando o download foi iniciado, você pode excluir o arquivo como TRS-80 disse. Mas eu não recomendaria isso, porque se o seu cliente for desconectado por qualquer motivo, não será possível reiniciar o download. Então eu iria analisar o arquivo de logs para saber quando o arquivo foi baixado. A entrada no arquivo de log não será adicionada até que a conexão com o cliente seja fechada. No arquivo de log, você terá o número de octetos exibidos para o cliente, para que você possa compará-los com o tamanho do arquivo para ter certeza de que ele fez o download do arquivo inteiro.

    
por 04.07.2009 / 05:26
1

Eu proporia uma solução mais elegante:

O Apache é capaz de log condicional, e o log pode ser enviado para um processo. Então você pode fazer algo como:

SetEnvIf Request_URI "^/path/to/files/.*\.zip$" deletefile
CustomLog "|/path/to/program" "%r" env=deletefile

O programa obterá o nome do arquivo depois que cada solicitação terminar e poderá excluí-lo:

#!/usr/bin/perl
$| = 1;
while (<STDIN>) {
    unlink($_);
}

Você pode até usar "% > s% r" como formato e excluir somente se o status for 200.

    
por 12.08.2009 / 23:26
0

Esta não é uma resposta definitiva, mas como eu pensaria primeiro em lidar com isso.

Eu corria um script a cada hora. Esse script enumeraria todos os nomes de arquivos na pasta de origem Zip. Em seguida, obtive o script para ler os logs do Apache para algum tipo de entrada de conclusão de transferência correspondente ao nome de arquivo atual. Se houver uma entrada de log correspondente, exclua o arquivo. Caso contrário, passe para o próximo nome de arquivo.

    
por 03.07.2009 / 18:51
0

Há ótimas informações nessa página. Eu não me sinto valor sequer para contribuir devido à esperteza da abordagem do TRS-80. O que me preocupa, porém, é que você está servindo arquivos enormes gerados dinamicamente, mas estão preocupados com o espaço em disco. Eu quero ter certeza de que você está sendo sábio com seu recurso mais precioso, RAM.

Primeiro, você deve se certificar de que está fazendo as coisas de forma que o Apache possa utilizar sendfile . Eu também estaria preocupado em gerar o arquivo com qualquer camada de aplicação baseada em módulo, mod_php, mod_python ou proxy reverso para mongrel / Ruby on Rails. Você realmente precisa ser cauteloso com isso. Eu não sei muito sobre sua configuração, mas o instinto me diz que você deveria:

  1. Use o MPM do trabalhador em vez do Pre-Fork
  2. Se estiver usando o Python, consulte: WSGI Se estiver usando o PHP, consulte: FastCGI Se o Rails consultar: Passageiro
  3. Não deixe que os usuários solicitem o que aciona a geração do arquivo - faça a entrega. Use um padrão semelhante ao AJAX para:
    1. Geração de fila do arquivo
    2. Verifique periodicamente a conclusão
    3. Registrar que o download começou (bem, está prestes a)
    4. Iniciar o download
  4. No entanto, não confie no cliente para indicar que você deve remover o arquivo. Eu usaria periodicamente lsof no "log iniciado" para remoção.

Naturalmente, na minha indústria, sempre temos que nos preocupar com a possibilidade de escalar. Você pode não se importar.

    
por 07.08.2009 / 20:53
0

Como outra opção - tenho um processo semelhante, mas não escrevo nada em disco, pois atendo arquivos multi-GB.

Em vez disso, apenas emito os cabeçalhos HTTP apropriados (incluindo Content-Disposition para definir o nome do arquivo) e, em seguida, entrego para o zip (ou tar) com os sinalizadores apropriados para que eles gravem no stdout.

Quanto ao dimensionamento - tenho arquivos grandes, mas não os envio com frequência. Eu faço passar por 'legal' para poder abandonar a prioridade do processo de arquivamento.

Minha única preocupação com o meu sistema é a incapacidade de recuperar uma transferência parcial sem começar de novo, mas você especificamente disse que deseja limpar transferências bem-sucedidas e mal-sucedidas.

    
por 12.08.2009 / 21:43