Question

Je sais qu'il ya un tas d'API là-bas qui font cela, mais je sais aussi que l'environnement d'hébergement (étant d'ASP.NET) impose des restrictions sur ce que vous pouvez faire de manière fiable dans un thread séparé.

Je pourrais être complètement faux, alors s'il vous plaît me corriger si je suis, c'est cependant ce que je pense que je sais.

  • Une demande généralement les délais d'attente au bout de 120 secondes (ce qui est configurable) mais finalement le temps d'exécution ASP.NET va tuer une demande qui prend trop de temps pour terminer.
  • L'environnement d'hébergement, IIS généralement, emploie le recyclage des procédés et peut à tout moment décider de recycler votre application. Lorsque cela se produit toutes les discussions sont avortés et le redémarrage de l'application. Je ne suis cependant pas certain agressif, il est, ce serait un peu stupide de supposer qu'il serait abandonner une requête HTTP en cours normal, mais j'attendre à abandonner un fil, car il ne sait rien à propos de l'unité du travail d'un fil.

Si vous deviez créer un modèle de programmation facilement et de manière fiable et mettre théoriquement une tâche longue course, qui aurait à courir pendant des jours, comment voulez-vous accomplir cela à partir d'une application ASP.NET?

Voici mes réflexions sur la question:

J'ai pensé longtemps la ligne d'hébergement d'un service WCF dans un service de win32. Et parler au service via WCF. Ceci est cependant pas très pratique, parce que la seule raison pour laquelle je choisirais de le faire, est d'envoyer des tâches (unités de travail) de plusieurs applications Web différentes. Je puis finalement demander le service des mises à jour de statut et d'agir en conséquence. Ma plus grande préoccupation est que ce ne serait pas une grande expérience particulière si je devais déployer toutes les tâches au service pour qu'il soit en mesure d'exécuter certaines instructions. Il y a aussi cette question de l'entrée, comment pourrais-je alimenter ce service avec des données si j'avais un grand ensemble de données et nécessaires à mâcher à travers elle?

Ce que je fais en général est en ce moment ce

SELECT TOP 10 * 
FROM WorkItem WITH (ROWLOCK, UPDLOCK, READPAST)
WHERE WorkCompleted IS NULL

Il me permet d'utiliser une base de données SQL Server en tant que une file d'attente de travail et la base de données périodiquement sondage avec cette requête pour le travail. Si l'élément de travail terminé avec succès, je marque comme fait et continuer jusqu'à ce qu'il n'y a plus rien à faire. Ce que je n'aime pas que je pourrais théoriquement être interrompu à tout moment et si je suis entre le succès et le marquage comme fait, je pourrais finir par traiter le même poste de travail deux fois. Je pourrais être un peu paranoïaque et cela pourrait être tout va bien, mais si je comprends bien, il n'y a aucune garantie que cela ne se produira ...

Je sais qu'il ya eu des questions similaires sur le SO avant, mais non répond vraiment à une réponse définitive. C'est une chose vraiment commune, mais l'environnement d'hébergement ASP.NET est mal équipé pour gérer le travail de longue durée.

S'il vous plaît partager vos pensées.

Était-ce utile?

La solution

John,

Je suis d'accord que ASP.NET ne convient pas aux tâches Async que vous avez décrites eux, ne devrait pas être. Il est conçu comme une plate-forme d'hébergement web, pas un arrière processeur maison.

Nous avons eu des situations similaires dans le passé et nous avons utilisé une solution similaire à ce que vous avez décrit. En résumé, gardez votre service WCF sous ASP.NET, utilisez une table « file d'attente » avec un service Windows comme « QueueProcessor ». Le client doit interroger pour voir si le travail est fait (ou utiliser la messagerie pour informer le client).

Nous avons utilisé une table qui contenait le processus et il y a des informations (par exemple InvoicingRun). Sur cette table était un statut (en attente, en cours, terminé, a échoué). Le client présenterait une nouvelle InvoicingRun avec un statut d'attente. Un service Windows (le processeur) serait interroger la base de données pour obtenir des pistes que dans la scène en attente (vous pouvez aussi utiliser la notification SQL afin que vous ne avez pas besoin de sondage. Si on a trouvé une course dans l'attente, il se déplacerait à courir, faire le traitement et le déplacer vers achevé / échec.

Dans le cas où le processus n'a pas fatalement (par exemple DB vers le bas, le processus tués), la course serait laissé dans un état de fonctionnement, et l'intervention humaine est nécessaire. Si le processus a échoué dans un état non-fatale (exception, erreur), le processus serait déplacé à échoué, et vous pouvez choisir de réessayer ou avoir intervantion humain.

S'il y avait plusieurs processeurs, le premier à le déplacer à un état de fonctionnement a obtenu ce travail. Vous pouvez utiliser cette méthode pour empêcher le travail exécuté deux fois. Autre est de faire la mise à jour puis sélectionnez à l'exécution dans une transaction. Assurez-vous que l'un de ces en dehors d'une opération de transaction plus importante. Exemple (brut) SQL:

UPDATE InvoicingRun
SET Status = 2 -- Running
WHERE ID = 1
    AND Status = 1 -- Pending

IF @@RowCount = 0
    SELECT Cast(0 as bit)
ELSE
    SELECT Cast(1 as bit)

Rob

Autres conseils

Jetez un oeil à NServiceBus

  

NServiceBus est une source ouverte   Cadre de communication avec .NET   construire à l'appui pour publish / subscribe   et processus de longue durée.

Il est une construction technologique sur MSMQ, ce qui signifie que vos messages ne se perdent pas, car ils sont conservés sur le disque. Néanmoins, le cadre a une performance impressionnante et une API intuitive.

Ont pensé à l'utilisation du Workflow Foundation au lieu de votre implémentation personnalisée? Il vous permet également de persistez états. Les tâches peuvent être définies comme des flux de travail dans ce cas.

Juste quelques pensées ...

Michael

Utilisez une des tâches simples de fond / cadre d'emplois comme hangfire et appliquer ces meilleures pratiques des directeurs à la conception du reste de votre solution:

  • Gardez toutes les actions aussi faible que possible; Pour ce faire, vous devriez -
  • Diviser en cours d'exécution à long emplois en lots et les file d'attente (dans une file d'attente ou hangfire sur un bus d'une autre sorte)
  • Assurez-vous que vos petits travaux (pièces de longues emplois par lots) sont idempotent (ont tout le contexte dont ils ont besoin pour exécuter dans l'ordre). De cette façon, vous ne devez pas utiliser une quete qui maintient une séquence; parce que vous pouvez alors
  • paralléliser l'exécution des travaux dans votre file d'attente en fonction du nombre de nœuds que vous avez dans votre batterie de serveurs Web. Vous pouvez même contrôler la quantité de charge cette assujettit votre ferme (comme un échange au service des demandes Web). Cela garantit que vous avez terminé tout le travail (tous les lots) aussi rapidement et aussi efficacement que possible, sans compromettre votre cluster de service clients Web.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top