Manutenção de tarefas em segundo plano em um site grande

49

Estamos lidando com um problema interessante no StackOverflow.

Temos um monte de pequenas tarefas "precisam ser feitas em breve". Um exemplo está atualizando as listas "Perguntas relacionadas". O que fizemos no passado é retroceder essas tarefas nas cargas de página de alguns usuários.

Isso nunca foi o ideal, mas não era realmente perceptível. Agora que o SO ultrapassou os 1.000.000 pontos de interrogação, esses infelizes usuários estão começando a sentir isso.

A solução natural é realmente colocar essas tarefas em segundo plano. Estou pensando em duas maneiras amplas de fazer isso.

1. No IIS como um Thread-Pool / Work-Queue personalizado

Basicamente, criamos alguns threads (não ThreadPool , para não interferir no IIS) e os serviços de algumas coleções nas quais estamos inserindo Funcs .

O grande profissional aqui é a simplicidade. Não precisamos nos preocupar em organizar nada, nem precisamos garantir que algum serviço externo esteja pronto e respondendo.

Também temos acesso a todo o nosso código comum.

O golpe é, bem, que não devemos usar threads de segundo plano. As objeções que eu conheço estão todas centradas no IIS faminto (se você usa o ThreadPool) e os threads morrem aleatoriamente (devido à reciclagem do AppPool).

Temos a infraestrutura existente para tornar a morte aleatória do encadeamento um problema (é possível detectar uma tarefa foi basicamente abandonada) e limitar o número de encadeamentos (e usar encadeamentos que não sejam do ThreadPool) também não é difícil.

Estou perdendo outras objeções no processo de agrupamento de threads / filas de trabalho do IIS?

Movido para StackOverflow , pois não foi realmente abordado aqui.

2. Como serviço

Alguma solução de terceiros ou uma solução personalizada.

Basicamente, organizávamos uma tarefa através do limite do processo para algum serviço e simplesmente a esquecíamos. Presumivelmente, estamos vinculando algum código ou restritos ao SQL bruto + uma cadeia de conexão.

O profissional é que é o "caminho certo" para fazer isso.

Os contras são que somos muito restritos no que podemos fazer ou teremos que elaborar algum sistema para manter esse serviço sincronizado com nossa base de códigos. Também precisamos conectar todo o nosso monitoramento e registro de erros de alguma forma, que obtemos gratuitamente com a opção "No IIS".

Existem outros benefícios ou problemas com a abordagem de serviço?

Em poucas palavras, existem problemas imprevisíveis e intransponíveis que tornam a abordagem nº 1 impraticável? Em caso afirmativo, existem bons serviços de terceiros nos quais devemos procurar a abordagem nº 2?

Kevin Montrose
fonte
O caminho certo é o caminho que, quando você decide ir para o outro lado, olha para trás e diz que deveríamos ter feito o caminho certo. Escolha sabiamente. Eu não estou familiarizado o suficiente com o mundo IIS para comentar sobre esse problema específico.
Chris
2
Estou curioso, porque tenho um cenário semelhante (em uma escala muito menor) e também estou apoiando em alguns usuários aleatórios a conexão infeliz. Não estou familiarizado com a melhor solução, por isso vou seguir aqui. :-)
pc1oad1etter 22/10/10
7
Não entendo por que isso não está no StackOverflow. Isso é uma troca de engenharia, não uma avaliação subjetiva. Você está pedindo uma análise das diferentes abordagens - isso é tudo objetivo. Somente quando a análise deixa claro quais são exatamente as vantagens e desvantagens, há alguma subjetividade a ela e, tanto quanto posso ver, sua pergunta não é 'o que devo achar mais importante, meu tempo e recursos do servidor ou o tempo do usuário? " ou algo semelhante.
Joren
@ Kevin Montrose - pelos seus comentários, parece que você está fazendo uma distinção entre "precisa ser feito em breve" e "programado em um intervalo". Você pode explicar por que esses são dois tipos diferentes de tarefas em segundo plano que requerem um padrão / infraestrutura diferente?
Portman
@Portman - A diferença fundamental é que tarefas "em breve" não podem ser feitas especulativamente, precisamos realmente esperar até sabermos que elas precisam ser feitas. Alguns cálculos no verso do envelope mostram que, se movermos as consultas de "Questões relacionadas" (apenas uma de muitas) para uma guia cron "burra", levaria aprox. uma semana de sólida execução para solucionar todas as perguntas. Geralmente, também queremos que eles sejam executados o mais rápido possível (sem afetar a experiência do usuário), enquanto nossas tarefas de intervalo podem ser executadas não mais que uma vez em 5 minutos (e normalmente com muito menos frequência).
Kevin Montrose

Respostas:

17

Algumas semanas atrás, fiz uma pergunta semelhante no SO. Em uma casca de noz, minha abordagem já há algum tempo foi desenvolver um serviço do Windows. Eu usaria o NServiceBus (essencialmente MSMQ nos bastidores) para reunir solicitações do meu aplicativo da web para o meu serviço. Eu costumava usar o WCF, mas fazer com que uma transação distribuída funcionasse corretamente no WCF sempre parecia uma chatice. O NServiceBus fez o truque, eu poderia confirmar dados e criar tarefas em uma transação e não me preocupar se meu serviço estava funcionando naquele momento. Como um exemplo simples, se eu precisasse enviar um email (por exemplo, um email de registro), criaria a conta do usuário e dispararia um sinal para o meu Serviço Windows (para enviar o email) em uma transação. O manipulador de mensagens no lado do serviço captaria a mensagem e processaria adequadamente.

Desde que o ASP .NET 4.0 e o AppFabric foram lançados, existem várias alternativas viáveis ​​para o mecanismo acima. Voltando à pergunta mencionada acima, agora temos o AppInitialize do AppFabric (via net.pipe) e o recurso Auto-Start do ASP .NET 4.0, que tornam o desenvolvimento do Windows Services como aplicativos da Web uma alternativa viável. Comecei a fazer isso agora por várias razões (a maior delas sendo a implantação não é mais um pé no saco):

  1. Você pode desenvolver uma interface de usuário da web sobre o seu serviço (já que está sendo executado como um aplicativo da web). Isso é extremamente útil para ver o que está acontecendo no tempo de execução.
  2. Seu modelo de implantação para seus aplicativos da web funcionará para seu aplicativo de serviço.
  3. O IIS fornece alguns recursos interessantes para lidar com falhas de aplicativos (semelhantes em alguns aspectos a um serviço do Windows).
  4. Os desenvolvedores da Web estão muito familiarizados com o desenvolvimento de aplicativos da Web (naturalmente), a maioria não sabe muito sobre as melhores práticas ao desenvolver um serviço do Windows.
  5. Ele fornece várias alternativas para expor uma API para outros aplicativos consumirem.

Se você seguir esse caminho (perdoe-me por copiar e colar da minha postagem original), eu definitivamente consideraria executar a lógica de segundo plano em um aplicativo Web separado. Existem várias razões para isso:

  1. Segurança . Pode haver um modelo de segurança diferente para a interface do usuário que exibe informações sobre os processos em segundo plano em execução. Eu não gostaria de expor essa interface do usuário a mais ninguém, exceto à equipe de operações. Além disso, o aplicativo Web pode ser executado como um usuário diferente, com um conjunto elevado de permissões.
  2. Manutenção . Seria ótimo poder implantar alterações no aplicativo que hospeda os processos em segundo plano sem afetar o usuário usando o site de front-end.
  3. Performance . Separar o aplicativo do site principal que processa solicitações do usuário significa que os encadeamentos em segundo plano não diminuirão a capacidade do IIS de lidar com a fila de solicitações recebidas. Além disso, o aplicativo que processa as tarefas em segundo plano pode ser implantado em um servidor separado, se necessário.

Fazer isso volta ao aspecto empacotamento. WCF, NServiceBus / RabbitMQ / ActiveMQ etc., MSMQ de baunilha, API RESTful (pense MVC) são todas as opções. Se você estiver usando o Windows Workflow 4.0, poderá expor um ponto de extremidade do host que seu aplicativo Web possa consumir.

A abordagem de hospedagem na web para serviços ainda é relativamente nova para mim, apenas o tempo dirá se foi a escolha correta. Até agora está bom. A propósito, se você não quiser usar o AppFabric (eu não poderia, por algum motivo bizarro, o Windows Server Web Edition não é suportado), o recurso de Inicialização Automática mencionado na publicação do Gu funciona bem. Porém, fique longe do arquivo applicationhost.config, é possível configurar tudo nesse post através do console do IIS (Editor de Configuração no nível do servidor principal).

Nota: Originalmente, eu havia postado mais alguns links nesta mensagem, mas, infelizmente, este é o meu primeiro post nesta troca e apenas um link é suportado! Havia basicamente dois outros, para obter o Google "Death to Windows Services ... Long Live AppFabric!" e "auto-start-asp-net-applications". Me desculpe por isso.

Rohland
fonte
A idéia básica de usar um site separado como o serviço é uma questão intrigante que eu não tinha considerado ...
Kevin Montrose
Rohland, posso estar faltando alguma coisa aqui, mas você parece estar dizendo que estava interagindo com um Serviço Windows de dentro do seu manipulador NServiceBus, o serviço envia o email. Se estiver certo, posso perguntar por que você simplesmente não envia o email de um manipulador de mensagens NServiceBus, o que seria muito fácil de desenvolver, testar e implantar?
precisa saber é o seguinte
O site envia uma mensagem para o Serviço Windows. O manipulador de mensagens NServiceBus do Windows Service pega a mensagem e a envia. Em essência, é o mesmo que o processo que você descreve.
Rohland
22

Na verdade, existe uma terceira maneira no Windows de executar serviços em segundo plano, e isso é muito comum no mundo UNIX. A terceira maneira é um CRONtrabalho que executa uma parte da sua infraestrutura. No Windows, isso é conhecido como task schedulere é muito comum para executar código de forma programada. Para usar isso, você criaria um aplicativo de linha de comando que é executado em um agendamento predefinido. A vantagem disso é que você não precisa se preocupar se o processo permanecer ativo e funcionando como um serviço, porque, se por algum motivo falhar, será iniciado na próxima vez.

Quanto à organização de tarefas específicas, você realmente só precisa armazenar essas tarefas em um armazenamento binário persistente. Até que o aplicativo da linha de comando os retire do armazenamento e os execute. Eu fiz isso no passado usando o banco de dados do Cassandra como um provedor de estado de sessão para preencher tarefas em segundo plano para usuários específicos no banco de dados do Cassandra e depois fazer com que a linha de comando os escolha e execute-os para o usuário.

Essa pode não ter sido a solução típica de empacotamento, mas funcionou muito bem para mim e acabou sendo uma solução muito elegante, porque as tarefas agendadas sobreviveram a desligamentos, problemas de rede e qualquer máquina poderia executar a tarefa, pois estava centralmente armazenado.

Promoção vergonhosa, mas este é o meu projeto e a solução que acabei de detalhar brevemente é por que criei o projeto: http://github.com/managedfusion/fluentcassandra/

Nick Berardi
fonte
2
Faço isso com meu serviço de hospedagem compartilhada, pois não tenho acesso ao shell. Escreva uma página PHP que faça algo importante e, em seguida, faça um trabalho cron que carregue a página usando o wget ou o lynx periodicamente. Isso parece exatamente o tipo de coisa que funcionaria nesse caso e seria extremamente simples, dificilmente exigindo uma alteração na maneira como as coisas são feitas atualmente.
Ricket 22/10/10
Que solução simples. Isso gerou idéias para o meu próprio projeto que eu nem estava pensando ainda. Além disso, você tem acesso total à sua base de código existente. Basta adicionar um projeto de console à solução e referenciar os projetos existentes.
Tim Murphy
10

Aplicativo Cron + Web

Esse é um design testado em batalha que se adapta horizontalmente ao seu web farm e garante que você esteja usando a pilha de tecnologias da web que você já conhece.

Veja como funciona:

  1. Crie um controlador / ação em seu aplicativo da web para lidar com tarefas em segundo plano agendadas. Por convenção, eu costumo chamar de meu http://mydomain.com/system/cron.
  2. Por segurança, essa ação deve ser bloqueada para apenas endereços IP autenticados na rede local.
  3. Em uma máquina separada, instale o Wget e configure uma Tarefa agendada para que o wget busque o recurso da etapa 1. Você pode executar a tarefa com a frequência que desejar (geralmente eu opto por 30 segundos). Não esqueça de passar o argumento de cookie apropriado para o Wget para que ele se autentique no seu aplicativo da web.
  4. Para redundância, você também pode instalar um segundo wget agendado em uma segunda máquina.

Viva! Agora você tem uma rota que será chamada a cada 30 segundos. E se a solicitação demorar 5 minutos para processar, ninguém se importará, porque não faz parte da solicitação de página do usuário.

A cronação acaba parecendo muito simples: ele tem uma lista de métodos para executar em uma determinada frequência. Quando uma solicitação chega, ele vê se existe um método que precisa ser executado e chama o método apropriado. Isso significa que você pode controlar o agendamento em seu banco de dados , onde provavelmente já possui muitos outros dados de configuração importantes para o seu site.

Mais importante (para você), isso significa que seus trabalhos não precisam ser chamados em um horário fixo. Você pode escrever qualquer lógica que desejar para determinar quando executar um método.

Prós e contras

Prós
  • Você já é muito bom em escrever código ASP.NET MVC; portanto, você pode escrever suas tarefas em segundo plano na mesma plataforma em que você escreve o restante da sua solução.
  • As tarefas são executadas no mesmo contexto que seu aplicativo Web, para que você possa compartilhar o cache e usar os métodos auxiliares que já existem.
  • Se você deseja buscar um URI com balanceamento de carga , suas tarefas em segundo plano agora também são com balanceamento de carga.
  • Implantação simultânea - você não precisa se preocupar em sincronizar seu aplicativo Web com sua lógica de tarefas em segundo plano, porque todos estão na mesma implantação.
Contras
  • Ao longo dos anos, algumas pessoas me disseram que esse design é "altamente acoplado", mas, quando pressionadas, não foram capazes de explicar por que isso é uma coisa ruim.

Nota: Se houver alguma dúvida ou preocupação, adicione um comentário . Fico feliz em elaborar.

Portman
fonte
7

Eu tentei e usei praticamente todas as maneiras possíveis de fazer isso no meu aplicativo atual. Comecei a fazer a mesma coisa que você faz atualmente, seguindo uma solicitação do usuário para preencher os dados e depois armazená-los em cache. Percebi que isso também era uma má ideia (especialmente quando você escala em vários servidores da Web, mais usuários sofrem).

Também tive um trabalho agendado que atinge uma URL no aplicativo ASP.NET - esta é uma solução decente, mas começa a quebrar no minuto em que você passa de 1 servidor da web.

Atualmente, eu uso dois métodos diferentes, ambos usando o Quartz.NET, que é uma ótima e pequena biblioteca. O primeiro é o Quartz.NET em execução no ASP.NET, é configurado no global.asax e é executado a cada dois minutos. Eu uso isso para atualizar o cache do ASP.NET fora da banda, que é a única razão pela qual ele é executado como parte do ASP.NET.

A segunda é que eu escrevi uma biblioteca para agrupar o Quartz.NET chamado DaemonMaster - facilita colocar uma DLL em um diretório e executá-lo em um serviço do Windows. Achei que isso ajuda a evitar algumas das partes irritantes do trabalho com um Serviço Windows e também limpa a API do Quartz.NET. Os serviços executados no DaemonMaster são de dois tipos diferentes, o primeiro são trabalhos que precisam ser executados todas as noites ou a cada X minuto. Os outros trabalhos funcionam fora de uma fila com base nos dados provenientes do aplicativo ASP.NET. O aplicativo ASP.NET descarta objetos JSON no RabbitMQ e a pesquisa de serviços RabbitMQ processa os dados.

Com base nisso, sugiro que você use um serviço do Windows (e confira o DaemonMaster) e, se necessário, use uma fila como o RabbitMQ para passar os dados do aplicativo ASP.NET para os serviços - ele funcionou da melhor maneira possível em todas essas soluções . Se você estiver carregando o cache, a execução no ASP.NET faz sentido; caso contrário, acho que não.

James Avery
fonte
6

Eu faria da maneira certa e teria um serviço do Windows em execução que monitora uma "fila". Eu digo "fila" porque a programação w / MSMQ é semelhante a furar jogadores quentes em seus olhos.

Eu me apaixonei pela simplicidade do Delayed :: Job in Rails, e algo semelhante poderia ser feito facilmente no .NET.

Basicamente, você adiciona qualquer tipo de SomethingOperation(algo que possui um Perform()método). Em seguida, basta serializar os parâmetros relevantes, dar prioridade a ele, algum tipo de comportamento de nova tentativa padrão e colocá-lo em um banco de dados.

Seu serviço apenas monitoraria isso e trabalharia os trabalhos na fila.

Ben Scheirman
fonte
Serializar os parâmetros relevantes não é realmente um "justo", é quase o "tudo". É um dos meus maiores reservas sobre a abordagem processo separado ...
Kevin Montrose
Sim, essa é a mesma solução que eu usei, no entanto, serializei o objeto inteiro no banco de dados como um binário e os puxei para execução. Usei Cassandra como meu armazenamento persistente e o Agendador de tarefas como meu agendador CRON para o aplicativo de linha de comando que executaria e executaria as tarefas.
precisa
Começamos incluindo apenas um simples dado na mensagem e acabamos jogando o objeto inteiro. Ainda funcionou muito bem. Eu consideraria a separação, pois tem outros benefícios também.
Nathan Palmer
@ Kevin - se ao menos tivéssemos algumas pessoas com muita história de serialização ...
Marc Gravell
4

Ficamos muito felizes com a abordagem do Barramento de Serviço / Fila de Mensagens / Serviço. A arquitetura básica é essa.

O site envia mensagem para a fila

bus.Send(new ProjectApproved()); // returns immediately

O serviço Windows recebe e processa mensagens em seu próprio tempo

public class DoesSomethingAwesome : ConsumerOf<ProjectApproved>
{
   public void Consume(ProjectApproved Message)
   {
      // Do something "offline"
   }
}

A vantagem é que não há atraso para o serviço front-end ao qual os usuários também estão conectados. O serviço do Windows pode ser desligado e atualizado sem interrupção para o site principal. Além disso, é extremamente rápido .

Se você não conseguir armazenar todos os seus dados na mensagem, sempre poderá armazená-los e recuperá-los mais tarde. Sugiro usar um mecanismo de armazenamento de documentos como: RavenDB ou MongoDB, onde é muito simples armazenar suas classes sem alterações.

O site envia mensagem para a fila

// Save your object
store.Save(completeProject);

// Send a message indicating its ready to be processed
bus.Send(new ProjectApproved() { ProjectId = completeProject.Id });

O serviço Windows recebe e processa mensagens em seu próprio tempo

public class DoesSomethingAwesome : ConsumerOf<ProjectApproved>
{
   public void Consume(ProjectApproved Message)
   {
      // Retrieve your object back
      var completeProject = store.Get(Message.ProjectId);
   }
}

Para simplificar, usamos: Rhino ESB e Topshelf . A configuração é extremamente simples e colocar isso em prática para um aplicativo existente provou levar muito pouco tempo.

Nathan Palmer
fonte
De qualquer forma, usando um barramento de serviço com CQRS é sempre uma boa maneira de melhorar a sua escalabilidade
thinkbeforecoding
3

Estou curioso para saber por que uma combinação dos dois não é uma opção viável. No momento, você aciona trabalhos nas exibições de página, com alguma seiva infeliz aguardando 10 segundos para que a página seja exibida. Pelo menos essa é a minha compreensão do seu método atual.

No entanto, esses trabalhos estão demorando mais e mais para serem executados à medida que o site cresce, e você não deseja prejudicar a experiência do usuário no site. Nem mesmo para alguns (ou talvez muito) usuários azarados ao longo do dia, agora você está pensando em agendar trabalhos em segundo plano.

Não vejo por que um trabalho em segundo plano executado em intervalos regulares não pode imitar um visitante. Agora não sou programador do Windows, mas no mundo Linux eu configuraria um trabalho cron que é executado em intervalos regulares e teria duas linhas de código.

#!/bin/bash
wget -O /dev/null http://stackoverflow.com/specially_crafted_url

Combina os profissionais de ambos os sistemas. É feito em segundo plano. Não afeta os usuários. Ele ainda usa uma visualização de página para iniciar o trabalho. Eu já vi essa abordagem usada antes. Tende a ser o meio termo entre os modos simples da antiguidade e os modos mais complexos que aparecem na estrada.

Atualizar

Acho que você pode solucionar o problema de balanceamento de carga executando os executores de tarefas nos próprios servidores da web. O executor de tarefas extrai uma URL da fila de tarefas e a executa da seguinte maneira:

wget -O /dev/null http://localhost/specially_crafted_url

Devido à natureza das filas de tarefas / mensagens, as tarefas serão distribuídas igualmente entre os executores de tarefas, o que significa que a URL especialmente criada é eventualmente distribuída entre os servidores da Web.

mellowsoon
fonte
Já fazemos isso para tudo o que é executado em intervalos previsíveis, o que nos resta são coisas que não podem ser previstas com muita antecedência. Por exemplo, o "bloco de perguntas relacionadas" é atualizado apenas em perguntas que foram visualizadas recentemente. Da mesma forma, as listas de perguntas marcadas serão armazenadas em cache apenas se alguém quiser verificar essas tags. Como temos mais de um milhão de perguntas e abordamos 25 mil tags, não podemos executar todas as tarefas associadas (e são apenas dois exemplos) "por precaução".
Kevin Montrose
Também há problemas de equilíbrio de carga, pois o SO é dividido em vários servidores. Basicamente, se você for ao stackoverflow.com, sempre acessará o mesmo servidor. A abordagem do wget nos forçaria a organizar todas as tarefas em um único servidor (ou realmente reformular nossa configuração de balanceamento de carga), o que seria realmente doloroso.
Kevin Montrose
Seja legal se as coisas funcionassem em intervalos regulares, não é? Entendo o que você está dizendo, mas a metodologia descrita acima (e acho que mencionada por algumas outras pessoas) não muda. Quando uma exibição de página diz "é hora de executar este trabalho", você o coloca em uma fila de mensagens. Um trabalho em segundo plano de longa execução executa os trabalhos que encontra. Nesse caso, os trabalhos nada mais são que URLs que precisam ser solicitados. hehe Você provavelmente pode configurá-lo em um servidor compartilhado de US $ 20 por mês, pois ele não precisa de sua base de código para ser executada. Dê uma olhada no Amazon SQS para obter um serviço de mensagens fácil de usar.
mellowsoon
Em relação aos problemas de balanceamento de carga. Onde há vontade, há um caminho! Em vez de fazer a solicitação para stackoverflow.com, você pode acessar um servidor aleatoriamente usando seu endereço IP. Se o balanceador de carga verificar cookies para solicitações de canal, você poderá falsificar cookies. Se ele verificar o endereço IP, você provavelmente pode até fingir isso (já que não se importa com a resposta do servidor).
mellowsoon
Concordou que o balanceamento de carga não deve ser uma razão para não fazer isso. Como a solicitação specially_crafted_urlé proveniente de um IP conhecido, você pode adicionar uma regra ao seu balanceador de carga para executar round-robin apenas para solicitações desse IP.
Portman
2

Eu acho que o golpe com a abordagem de serviço puro é que você tem código espalhado no serviço e longe do aplicativo principal.

Aqui está o que fizemos com grandes trabalhos em segundo plano, que não são sensíveis ao tempo, que mantêm o código unido e simplificam o serviço:

  1. Crie uma fila de trabalhos (na memória ou no banco de dados, independentemente da persistência necessária para os tipos de trabalhos)
  2. Crie um serviço da web que executará os trabalhos na fila
  3. O aplicativo de serviço simples inoperante que chama o serviço da Web em um intervalo especificado, deixa todas as coisas complexas (recuperação e execução de tarefas) para o serviço da Web em sua base de código principal.

Ainda mais simples, basta fazer a chamada em um aplicativo de console e usar o Agendador de tarefas ou o VisualCron para transformá-lo em um "serviço".

Brandon
fonte
11
Eu tenho exatamente isso em um aplicativo significativo no trabalho - um serviço do Windows que aciona o aplicativo Web em intervalos. O aplicativo da web permanece sem estado, puxando o estado do banco de dados conforme necessário. Funciona um prazer.
Bevan
1

Eu gostei do TopShelf. Mantém a simplicidade, mas ainda assim o executa da maneira correta como um serviço do Windows. Basicamente, crie um aplicativo de console, adicione de 15 a 20 linhas de código e ele será instalado como um serviço.

http://code.google.com/p/topshelf/

Shane
fonte
1

Que tal ter um serviço Windows muito simples que é executado no servidor da Web e periodicamente atinge uma URL de manutenção que executa suas tarefas diversas. Faça com que ele reduza a quantidade de trabalho que faz em qualquer solicitação.

Rob Sobers
fonte
1

Vou reverter a tendência aparente aqui e sugerir o uso do modelo no IIS. Eu mesmo usei e funciona muito bem. Realmente não é tão difícil implementar uma classe de pool de encadeamentos decente (ao longo dos anos, estendi minha classe de pool de encadeamentos para oferecer suporte à criação e destruição dinâmicas de encadeamentos, nova tentativa de tarefas e assim por diante). As vantagens são:

  • Nenhum serviço externo para monitorar
  • Simplicidade de implementação: sem organização entre processos, sem monitoramento avançado de tarefas
  • Você ainda está dentro do processo do IIS, portanto pode fazer todo o log usual e assim por diante (não há necessidade de vários arquivos de log)
  • Implantação amplamente simplificada (quando você atualiza um serviço, é necessário interromper o serviço, copiar os arquivos, iniciar o serviço - além das atualizações usuais no código do site)

Na minha opinião, uma solução no IIS é simplesmente o "próximo passo" de pegar o trabalho em exibições de página aleatórias.

Dean Harding
fonte
1

Resque é bom. Ou mesmo Kthxbye, se você precisar ser notificado sobre o valor resultante depois que ele for concluído.

Ambos Redis / Ruby baseados em tho.

Honestamente, se você está adotando uma abordagem baseada em serviços, ela realmente não precisa ser superintegrada à sua plataforma atual, o que eu acho que é uma vantagem. Eu esperava que pudesse ser um sistema de esquecer e executar (com algum tipo de monitoramento) e concluir tarefas. Não tenho certeza de que ele precise ser executado na mesma plataforma, pois apenas atualiza / modifica as informações do banco de dados.

Certamente você poderia se dar bem com muito mais por muito menos se você trabalhasse com esse tipo de trabalho em uma entidade separada, especialmente porque parece que você está lidando com problemas de segmentação. Ambos Resque e kthxbye mover o processamento fora de processos separados para permitir que o SO para lidar com a simultaneidade.

Resque

Kthxbye

Lukas
fonte
Devo tentar Kthxbye, apenas pelo grande nome!
Nathan Palmer
praticamente o incrível. próximo será o ORLY? biblioteca. provavelmente por estatísticas de monitoramento de algum tipo ...;)
Lukas
0

Eu usaria um serviço WCF hospedado pelo WAS ouvindo uma fila do MSMQ.

Pro's

  • Dispare e esqueça mensagens unidirecionais do aplicativo Web

  • Limitação e nova tentativa do MSMQ / WCF

  • Entrega garantida; D

  • Dead Letter management

  • Processo de distribuição

  • Ativação WAS / MSMQ

Con's

  • MSMQ (ainda não está morto ...)

Os recursos do MSMQ no WCF tornam o uso do MSMQ muito bom. Sim, você sangrará na configuração, mas os benefícios serão superiores ao sacrifício.


fonte
0

Eu me deparei com isso algumas vezes ao desenvolver aplicativos da web. Resolvemos isso criando um aplicativo de console do Windows que executa a tarefa e criando uma tarefa agendada que é executada de vez em quando para realmente executar a tarefa.

John Christensen
fonte
0

Você pode desviar o trabalho para um encadeamento em segundo plano (ou muitos encadeamentos em segundo plano) usando Rx e algo como o seguinte:

var scheduler = new EventLoopScheduler( SchedulerThreadName );
_workToDo = new Subject<Action>();
var queueSubscription = _workToDo.ObserveOn( scheduler ).Subscribe( work => work() );
_cleanup = new CompositeDisposable( queueSubscription, scheduler );

Usar:

var work = () => { ... };
_workToDo.OnNext( work ); // Can also put on error / on complete in here

Hospede tudo isso dentro de uma classe da qual existe apenas um (também conhecido como singleton, mas faça-o corretamente - use seu contêiner de IoC para determinar o estilo de vida).

Você pode controlar o tamanho do conjunto de encadeamentos etc. escrevendo um agendador personalizado no lugar do EventLoopScheduler (que executa um único encadeamento).

Neal
fonte
0

Eu implementei esse tipo de coisa algumas vezes. No Windows, configurei um programa de linha de comando python que faz algo em vários momentos. Este programa também expõe uma interface xmlrpc em uma porta. Em seguida, um trabalho de tarefa agendada é executado a cada minuto e consulta as interfaces xmlrpc. Se eles não estiverem ativos, ele tenta iniciá-los. Se não puder, ele me envia um e-mail.

A vantagem é que o trabalho executado não é cron ou agendado. Eu tenho um trabalho de processo que é executado a cada segundo, mas aguarda mais e mais tempo entre iniciar um novo trabalho, dependendo se ele tem trabalho a ser feito. Além disso, ele pode ser usado para agir de forma inteligente com base no resultado. Tem um erro de 500? Tem um atraso muito longo? Faça outra coisa. Notifique outro serviço. Etc.

E o mesmo sistema funciona em unix, com pequenas modificações.

Christopher Mahan
fonte
0

Eu não tenho uma resposta para você, mas o problema tocou um sino - lembro-me de alguns caras aleatórios discutindo isso em um podcast uma vez .

Spolsky: Percebi que uma das perguntas que você fez no blog foi: como você deve lidar com tarefas recorrentes de manutenção em geral?

Atwood: Sim.

Spolsky: Essa é uma caracterização justa? Todo site tem algumas tarefas que você não deseja executar no momento em que uma página da web está carregando, mas você deseja executar com algum tipo de recorrência.

Atwood: Sim, as tarefas em segundo plano são o tipo de coisa.

Spolsky: Sim, o que você descobriu?

Atwood: Bem, originalmente eu perguntei no Twitter, porque eu só queria algo leve. Eu realmente não queria escrever um serviço do Windows. Eu senti que isso estava fora do código da banda. Além disso, o código que realmente faz o trabalho é uma página da web, porque, para mim, uma unidade lógica de trabalho em um site é uma página da web. Então, é como se estivéssemos ligando de volta para o site, é como outra solicitação no site, então eu o vi como algo que deveria permanecer alinhado, e a pequena abordagem que surgimos que me foi recomendada no Twitter era essencialmente adicionar algo ao cache do aplicativo com uma expiração fixa, então você recebe uma chamada de volta. Quando isso expirar, ele chama uma determinada função que faz o trabalho e, em seguida, você o adiciona novamente ao cache com a mesma expiração.

Oddthinking
fonte
11
Sim, isso funciona para sites muito menores do que o StackOverflow se tornou. Infelizmente, a escala é um grande problema aqui (ou felizmente, dependendo de como você olha para ela).
Kevin Montrose
@ Kevin Montrose, defendo aqui a ignorância completa do domínio. Você poderia explicar por que uma página da web secreta (s) executa o trabalho (talvez em pequenas unidades) e ser chamada por uma atualização de página / cron em outro local que não é escalável? Não duvido que você esteja certo, mas adoraria aprender.
Oddthinking 22/10/10
sua sugestão específica (a data de expiração do cache) não é dimensionada porque todas as expirações de cache (no ASP.NET) executam um único thread (é um truque inteligente para sites menores, como costumava ser o SO). Uma tarefa cron não é escalável porque superamos um único servidor (o SO agora é 3 e ainda está crescendo) e qualquer tarefa cron atingia um único servidor (pelo menos, alterar essa invariável seria realmente doloroso com nossa carga- configuração do equilíbrio). Uma tarefa cron também precisa ser executada com muita frequência, pois essas tarefas são recorrentes na ordem de minutos.
Kevin Montrose
Vale a pena notar que usamos agendamento "estilo cron" para executar com menos frequência, intervalo fixo, tarefas já, coisas como concessões de crachás e avisos diários por email.
Kevin Montrose
0

Visão geral da API Java da fila de tarefas

Conceitos de tarefas
No processamento em segundo plano do App Engine, uma tarefa é uma descrição completa de uma pequena unidade de trabalho. Esta descrição consiste em duas partes:

  • Uma carga útil de dados que parametriza a tarefa.
  • Código que implementa a tarefa.

Tarefas como ganchos offline da Web
Felizmente, a Internet já oferece essa solução, na forma de uma solicitação HTTP e sua resposta. A carga útil dos dados é o conteúdo da solicitação HTTP, como variáveis ​​de formulário da web, XML, JSON ou dados binários codificados. A referência do código é o próprio URL; o código real é a lógica que o servidor executa ao preparar a resposta.

antony.trupe
fonte
Não estou sugerindo o uso da API da fila de tarefas do GAE, mas seguindo o modelo deles. Eles pensaram nisso por um tempo e escreveram uma implementação.
antony.trupe
0

Faz ambos

Adicione um parâmetro opcional ao caminho da pergunta que executa o trabalho que você está pegando carona nas solicitações do usuário:

Manutenção de tarefas em segundo plano em um site grande

Crie um aplicativo de console que seja executado em cada servidor, abra o binário compartilhado do log do IIS e o leia no final atual do arquivo. Use um observador de sistema de arquivos ou um intervalo de tempo para ler a frente e coletar atualizações enquanto o IIS descarregava o log.

Use essas informações para determinar quais páginas foram exibidas no momento.

Use os URLs da página do log analisado para chamar a versão "extrastuff" do URL no host local com um objeto de cliente da web.

Adicione algum código para alternar arquivos no final de cada período de log ou reinicie o processo a cada período de log.

Conta
fonte