Como recuperar de estado de trabalho inconsistente sem pesquisa de banco de dados

5

Estou trabalhando no escalonamento de um aplicativo que atualmente está pesquisando em um banco de dados mySQL para enviar tarefas assíncronas para um sistema de processamento em segundo plano.

Uma máquina de estado está sendo usada para acompanhar o progresso das entidades em todo o fluxo de trabalho. Por exemplo, podemos ter três estados:

  • Agendado
  • Processando
  • Conclua

Meu plano é adicionar um sistema de fila de mensagens para intermediar as tarefas enviadas para o sistema de processamento em segundo plano. Portanto, Application A inseria uma nova entidade e, em seguida, enviava uma mensagem para a fila. Application B consumiria essas mensagens e as rotearia para o trabalho de processamento em segundo plano correto.

def do_work(entity)
  # Precondition check
  raise "Wrong State" unless entity.scheduled?

  # Update state to processing
  entity.processing

  # ... do work

  # Update state to complete
  entity.complete
end

Dado um trabalho como o acima, estou com dificuldades para determinar como seria possível recuperar de uma situação em que havia um erro entre as transições de evento processing e complete . Por exemplo, uma falha no processo.

O processador de trabalho iria tentar novamente o trabalho, mas agora a entidade está em um estado inconsistente e falharia.

Como eu poderia lidar com este caso sem retornar a pesquisar a tabela de entidade procurando por trabalhos obsoletos?

Editar

Existem dois conceitos diferentes em jogo aqui. Nós temos os dados, e temos o estado dos dados no que se refere à execução do trabalho (programado / processamento) + o estado do fluxo de trabalho (completo).

Ambas as informações estão na mesma tabela. Assim, depois que os dados aumentam, o processo de pesquisa torna-se ineficiente (leituras / atualizações / inserções acontecem constantemente).

Portanto, talvez a solução seja ter Application B mover tarefas ativas para um armazenamento de dados separado. Assim, quando a tarefa de "limpeza" a que se refere @ Ӎσᶎ está em execução, o conjunto de dados deve ser muito menor.

Por fim, parece que não há como evitar o polling do banco de dados para garantir que os dados estejam no estado correto.

    
por Karl 26.03.2014 / 03:17
fonte

1 resposta

1

Vou considerar isso mais na forma de um plano de gerenciamento de riscos do que em um projeto de programa, porque é aí que o design do programa deve começar.

Parece que você tem dois canais de comunicação - o banco de dados e uma fila de mensagens. Assumiremos que o banco de dados é preciso, pois, se falhar, normalmente exigirá intervenção manual. Mas tudo o mais pode falhar, mesmo em circunstâncias improváveis (incêndios!)

O fluxo normal parece ser:

process a: 
     (1) create job
     (2) add to database
     (3) send message
process b: 
     (4) message received 
     (5) get job from database 
     (6) process job 
     (7) mark complete in database

Possivelmente, cada uma dessas etapas pode falhar. "criar trabalho" pode gerar um trabalho inválido (que não pode ser concluído, por exemplo) ou pode não conseguir recuperar as informações necessárias. Então você provavelmente vai querer algum tipo de mecanismo de relatório de erros (não, realmente:)

Observe que um deles pode ser resolvido tentando novamente (dados não disponíveis), mas o outro provavelmente desejará um mecanismo de detecção de erros - a tarefa de "limpeza". E a limpeza precisa categorizar os problemas como fixáveis ou não, de preferência tendo o código para consertá-los. Dessa forma, sua saída é um fluxo de processo normal e relatórios de erros, assim como todas as outras partes do programa.

Eu sugiro passar pelo seu código e pelo menos notar mentalmente a hierarquia de processamento de erros que você já tem, desde "se esta string puder ser transformada em um inteiro fazer ..." até "se houver uma exceção não tratada em algum lugar na o programa". O código de "limpeza" está mais alinhado com isso do que com a execução normal. É semelhante ao código de verificação de heap que programas como o valgrind possuem - você o executa periodicamente para garantir que o estado do programa esteja correto.

De uma forma ou de outra, você vai acabar com um thread ou processo em algum lugar que agende trabalhos. Bem no início (sua pergunta fala sobre o agendamento de trabalhos, em vez de apenas enfileirá-los), ou simplesmente executar a tarefa de limpeza. Se este último você pode ser capaz de executá-lo como um executável separado via cron (eu sugiro no Windows não se envolver com o equivalente, apenas a minha memória pessoal de ser um PITA para usar programaticamente. Uma das partes de "limpeza" é ter certeza que a tarefa agendada existe)

Você pode reduzir a frequência da tarefa de limpeza acionando-a manualmente nas etapas acima, quando houver certos tipos de erros (ou seja, se o processamento de um trabalho demorar mais do que o permitido, abandone-o e chame a limpeza). Se você pode torná-lo leve o suficiente, você pode ser capaz de executá-lo sempre que o passo 5 acima for executado, mas sugiro não fazer isso, mesmo que você possa inicialmente. Ou, pelo menos, teste-o com vários anos de dados em todas as suas tabelas.

Mas, independentemente disso, sugiro executá-lo na inicialização do programa e, em seguida, diariamente, para pegar coisas que você ainda não pensou. Tipo, o que acontece quando o seu programa é desligado? Quão rápido ele sai quando o computador é desligado e ele pode deixar um trabalho "pausado" para ser retomado ou ele tem tempo para redefinir o trabalho para "pronto para ser executado"? E se a tarefa do banco de dados para redefinir o trabalho expirar porque o banco de dados também está sendo encerrado?

(editar: mover dados para fora da tabela "fila" depois de processado acelera as coisas, e mais ainda ao longo do tempo à medida que o número de trabalhos processados aumenta. Dependendo da quantidade de dados e do número de falhas tem que lidar com isso, pode ser possível adicionar isso às etapas "obter trabalho" ou "marcar concluído". Mas isso é para tarefas simples

.

    
por 26.03.2014 / 22:57
fonte