Padrão para solicitações com tempos de resposta longos?

7

No momento, estamos mantendo um "servidor web" python caseiro, em que a geração de resposta para algumas solicitações pode demorar muito, principalmente devido a cálculos pesados ​​- essas solicitações são basicamente postagens com tempos limite muito longos (pense em minutos a dezenas de minutos).

Um problema dessa arquitetura é que às vezes há a necessidade de cancelar uma solicitação - por exemplo, o usuário notou um erro ao configurar a solicitação. Atualmente, o cancelamento é outra solicitação, que cancela a solicitação de longa execução - mas há muitas lacunas, por exemplo, o que acontece se o cliente simplesmente fechar o site?

Atualmente, estamos planejando retirar a abominação doméstica de um servidor da Web e mudar para algo sensato - por exemplo, Flask sendo executado dentro de um IIS usando o wfastcgi. Por razões políticas, o IIS está configurado, portanto, mudar para algo como gunicorn fica fora da janela.

Todo o desenvolvimento parou nisso porque ninguém tem uma idéia de como eliminar os processos executados pelo (w) fastcgi - essa preocupação simplesmente não faz parte das especificações do fastcgi.

Meu sentimento é que uma tentativa de criar algo que incorpore isso é um erro - eu preferiria uma solução em que o servidor simplesmente transferisse essas tarefas intensivas de computação para algum servidor em segundo plano (flask + aipo?) E as pesquisas de front-end para isso.

Infelizmente, a solução antiga estava em vigor por tanto tempo que alguns desenvolvedores querem manter o comportamento a todo custo.

Não sendo um servidor de web, eu gostaria de algumas dicas / padrões de como seriam as soluções sensatas para esse problema.

Christian Sauer
fonte

Respostas:

8

O que você está sugerindo está certo.

Deve ser assíncrono.

Você pode postar uma solicitação e ela fornecerá um ID exclusivo. Ele publica um Concluído neste ID exclusivo em alguma loja onde você pode pesquisar.

Se você precisar cancelar uma solicitação, uma solicitação de cancelamento usando o mesmo ID deve ser lançada.

Também no backend em que esses cálculos estão sendo executados, por exemplo, em uma interface de execução de um Thread (estilo java), você pode verificar após alguns segundos se o processo foi cancelado, verificando se uma postagem de cancelamento foi solicitada. Se for, o encadeamento deve sair. Esta é uma saída limpa. Você também pode usar uma interrupção no thread.

Aluno_101
fonte
IMHO, esta solução é a que melhor se adapta à abordagem 'sem estado' que se adapta tão bem ao Http - você separa o ato de fazer o cálculo da comunicação de solicitação / resposta. Nesse padrão, a comunicação de solicitação / resposta se torna uma conversa como esta: 'por favor, comece ... tudo bem, eu vou ... como você está? .. ainda trabalhando .. por favor cancele .. ok estou cancelando .. como você está? .. o cálculo foi cancelado .. por favor comece ... (espera) .. como você está? .. cálculo concluído aqui são os resultados. '.
Robert
2

Eu sugiro que você procure no wsgi e use multithreading . Você pode gerenciar cada solicitação em um encadeamento e implementar tempos limite no encadeamento. Você também deve poder gerenciar os encadeamentos e cancelar solicitações mais facilmente.

Tereus Scott
fonte
1

O problema que você enfrenta atualmente com uma simples postagem HTTP simplesmente não pode ser resolvido nesse protocolo. O HTTP funciona de forma assíncrona em cliente / servidor estrito, para que não haja notificações no servidor nem cancelamentos nativos. Além disso, você enfrentará o problema de respostas perdidas devido a tempos limite da rede na Internet. Vou sugerir uma abordagem diferente e moderna. Isenção de responsabilidade: pouco menos de 90% do suporte ao navegador

Eu sugiro que você inverta o fluxo de informações e use websockets. O que você precisa fazer quando uma tarefa é concluída é notificar seu usuário e enviar uma notificação de servidor para cliente.

Quando uma tarefa for publicada, ou, mais precisamente, como um substituto para a publicação, abra um websocket (use a tecnologia de servidor que você gosta, tornado, gevent, python-websocket etc.). Associe o encadeamento de tarefas no evento aberto do servidor websocket. Se o cliente sair, ele enviará um evento close ao seu manipulador de websocket, para que você possa finalizar o encadeamento associado a ele. Caso contrário, se sua tarefa terminar normalmente, o servidor poderá enviar os dados para o cliente e fechar o soquete da web. Além disso, você deve fazer o servidor executar ping uma vez a cada 30s, porque os websockets fecham se ficarem inativos por mais de um minuto.

Se você aplicar isso, será mais rápido e limpo do que uma pesquisa do lado do cliente, enquanto soluciona problemas de lacuna, pois você possui um canal bidirecional real. Observe que você pode implementar serviços adicionais sobre o esquema da tarefa, como sessões, pings de progressão etc.

Arthur Havlicek
fonte
0

Se sua tarefa precisar de muito tempo para ser concluída, não faça isso nesse pedido. Coloque na fila e faça outro processo que fará o trabalho.

Depois que o trabalho estiver concluído, basta enviar uma notificação ao usuário de que a "operação x" está concluída. Enquanto isso, mostre a mensagem "seu trabalho será concluído em aproximadamente x minutos".

Djuro
fonte