Nous traitons un problème intéressant sur StackOverflow.
Nous avons toute une série de petites tâches à accomplir rapidement. Un exemple est la mise à jour des listes "Questions connexes". Ce que nous avons fait par le passé est d’associer ces tâches au chargement de pages de certains utilisateurs.
Ce n'était jamais idéal, mais ce n'était pas vraiment perceptible. Maintenant que SO a dépassé le million de points d'interrogation, ces utilisateurs malchanceux commencent à le ressentir.
La solution naturelle est de pousser ces tâches en arrière-plan. J'envisage deux grandes façons de procéder.
1. Dans IIS en tant que pool de threads / file de travail personnalisé
Fondamentalement, nous mettons en place quelques threads (non ThreadPool , afin de ne pas interférer avec IIS) et les mettons au service de certaines collections dans lesquelles nous transférons des Funcs .
Le grand pro ici est la simplicité. Nous n'avons plus à nous soucier de rien, ni à nous assurer qu'un service externe est opérationnel et répond.
Nous avons également accès à tous nos codes communs.
Le problème est, eh bien, que nous ne devrions pas utiliser de threads d'arrière-plan. Les objections que je connais sont toutes centrées autour de l'IIS affamé (si vous utilisez ThreadPool) et des threads en train de mourir de manière aléatoire (en raison du recyclage AppPool).
Nous avons l'infrastructure existante pour que la mort aléatoire des threads ne soit plus un problème (la possibilité de détecter une tâche a été abandonnée, en gros), et il n'est pas difficile de limiter le nombre de threads (et d'utiliser des threads autres que ThreadPool).
Déplacé vers StackOverflow , car cela n'a pas vraiment été abordé ici.
2. En tant que service
Soit une solution tierce, soit une solution personnalisée.
En gros, nous regrouperions une tâche d'un service à un autre et l'oublierions. Vraisemblablement, nous lions du code dans, ou sommes limités à du SQL brut + une chaîne de connexion.
Le pro est que c'est la "bonne manière" de faire cela.
Les inconvénients sont que nous sommes soit très limités dans ce que nous pouvons faire, soit que nous allons devoir mettre au point un système pour maintenir ce service synchronisé avec notre base de code. Nous devrons également relier d’une manière ou d’une autre notre surveillance et notre enregistrement des erreurs, que nous obtenons gratuitement avec l’option "In IIS".
Y a-t-il d'autres avantages ou problèmes avec l'approche de service?
En un mot, existe-t-il des problèmes imprévus et insurmontables qui rendent l'approche n ° 1 inapplicable et, dans l'affirmative, existe-t-il de bons services tiers que nous devrions examiner pour l'approche n ° 2?
la source
Réponses:
Il y a quelques semaines, j'ai posé une question similaire sur SO. En résumé, mon approche consiste depuis quelque temps à développer un service Windows. J'utiliserais NServiceBus (essentiellement MSMQ sous les couvertures) pour regrouper les demandes de mon application Web à mon service. J'avais l'habitude d'utiliser WCF, mais le fait de faire fonctionner correctement une transaction distribuée sur WCF me semblait toujours être un casse-tête. NServiceBus a fait l'affaire, je pouvais valider des données et créer des tâches dans une transaction sans me soucier de savoir si mon service était opérationnel à ce moment-là. À titre d’exemple simple, si j’avais besoin d’envoyer un courrier électronique (par exemple, un courrier électronique d’enregistrement), je créerais le compte de l’utilisateur et enverrais un signal à mon service Windows (pour envoyer le courrier électronique) lors d’une transaction. Le gestionnaire de messages du côté service prendrait le message et le traiterait en conséquence.
Depuis que ASP .NET 4.0 et AppFabric ont été publiés, il existe un certain nombre d'alternatives viables au mécanisme ci-dessus. Pour revenir à la question que j'ai mentionnée ci-dessus, nous avons à présent AppInitialize d'AppFabric (via net.pipe), ainsi que la fonction de démarrage automatique d'ASP .NET 4.0, qui font du développement de Windows Services en tant qu'applications Web une alternative viable. J'ai commencé à le faire maintenant pour un certain nombre de raisons (la plus importante étant le déploiement n'est plus un problème):
Si vous choisissez cette voie (pardonnez-moi de copier et coller de mon message d'origine), je considérerais certainement d'exécuter la logique d'arrière-plan dans une application Web distincte. Il y a plusieurs raisons à cela:
Cela revient à l'aspect de marshaling. WCF, NServiceBus / RabbitMQ / ActiveMQ, etc., vanilla MSMQ, API RESTful (think MVC) sont toutes des options. Si vous utilisez Windows Workflow 4.0, vous pouvez exposer un point de terminaison hôte que votre application Web pourrait consommer.
L’approche de l’hébergement Web pour les services est encore relativement nouvelle pour moi, seul le temps nous dira s’il s’agissait du bon choix. Jusqu'ici tout va bien cependant. À propos, si vous ne voulez pas utiliser AppFabric (je ne pouvais pas parce que, pour une raison étrange, Windows Server Web Edition n'est pas pris en charge), la fonctionnalité de démarrage automatique mentionnée dans l'article de Gu fonctionne parfaitement. Éloignez-vous du fichier applicationhost.config, vous pouvez tout configurer dans la publication via la console IIS (Éditeur de configuration au niveau du serveur principal).
Remarque: à l'origine, j'avais posté quelques liens supplémentaires dans ce message, mais hélas, il s'agit de mon premier message à cet échange et un seul lien est pris en charge! Il y en avait essentiellement deux autres, pour les amener à Google "Mort aux services Windows ... Longue vie à AppFabric!" et "auto-start-asp-net-applications". Désolé pour ça.
la source
Il existe en réalité une troisième manière dans Windows d’exécuter des services d’arrière-plan et elle est très courante dans le monde UNIX. La troisième façon est un
CRON
travail qui gère une partie de votre infrastructure. Sous Windows, cela s'appelletask scheduler
et est très courant pour exécuter du code sur une base planifiée. Pour utiliser cela, vous créez une application de ligne de commande qui est exécutée selon un planning prédéfini. L'avantage de cela est que vous n'avez pas à vous inquiéter si le processus reste opérationnel comme un service, car s'il échouait pour une raison quelconque, il ne ferait que démarrer la prochaine fois.En ce qui concerne le marshaling de tâches spécifiques, il vous suffit de stocker ces tâches dans un stockage binaire persistant. Jusqu'à ce que l'application en ligne de commande les sélectionne et les exécute. Dans le passé, j'ai déjà utilisé la base de données Cassandra en tant que fournisseur d'état de session pour intégrer des tâches d'arrière-plan à des utilisateurs spécifiques de la base de données Cassandra, puis la ligne de commande les sélectionne et les exécute pour l'utilisateur.
Ce n'était peut-être pas la solution typique du marshaling, mais cela a très bien fonctionné pour moi et s'est avéré être une solution très élégante, car les tâches planifiées survivaient aux arrêts, aux problèmes de réseau, et n'importe quelle machine pouvait exécuter la tâche car elle était centralisée. stockée.
Promotion sans vergogne, mais ceci est mon projet et la solution que je viens de décrire brièvement est la raison pour laquelle j'ai créé le projet: http://github.com/managedfusion/fluentcassandra/
la source
Cron + Web App
Il s'agit d'une conception testée au combat qui s'adapte horizontalement à votre batterie de serveurs Web et garantit que vous utilisez la pile de technologies Web que vous connaissez déjà.
Voilà comment cela fonctionne:
http://mydomain.com/system/cron
.Hourra! Maintenant, vous avez un itinéraire qui sera appelé toutes les 30 secondes. Et si le traitement de la demande prend 5 minutes, personne ne s'en souciera, car cela ne fait pas partie de la demande de page d'un utilisateur.
L'
cron
action finit par paraître très simple: il dispose d'une liste de méthodes à exécuter sur une certaine fréquence. Lorsqu'une demande arrive, il voit s'il y a une méthode à exécuter et appelle la méthode appropriée. Cela signifie que vous pouvez contrôler la planification dans votre base de données , où vous avez probablement déjà beaucoup d'autres données de configuration importantes pour votre site.Plus important encore (pour vous), cela signifie que vos travaux ne doivent pas nécessairement être appelés selon un horaire fixe. Vous pouvez écrire n'importe quelle logique pour déterminer quand exécuter une méthode.
Avantages et inconvénients
AvantagesRemarque: S'il y a des questions ou des préoccupations, veuillez ajouter un commentaire . Je suis heureux d'élaborer.
la source
J'ai essayé et utilisé à peu près tous les moyens possibles de le faire dans mon application actuelle. J'ai commencé par faire la même chose que vous faites actuellement, à la suite d'une demande d'un utilisateur de remplir les données, puis de les mettre en cache à l'avenir. J'ai aussi compris que c'était une mauvaise idée (d'autant plus que vous utilisez plusieurs serveurs Web et que plus d'utilisateurs en prennent le coup).
J'ai également eu un travail planifié qui correspond à une URL dans l'application ASP.NET. Il s'agit d'une solution décente, mais qui commence à s'effriter à la minute près où vous passez devant un serveur Web.
Actuellement, j'utilise deux méthodes différentes, toutes deux utilisant Quartz.NET, qui est une excellente petite bibliothèque. La première est Quartz.NET qui s'exécute in-process avec ASP.NET, il est configuré dans le fichier global.asax et s'exécute toutes les deux minutes. J'utilise ceci pour mettre à jour le cache ASP.NET hors bande, ce qui est la seule raison pour laquelle il est exécuté dans le cadre d'ASP.NET.
La seconde est que j'ai écrit une bibliothèque pour emballer Quartz.NET appelée DaemonMaster - il est facile de déposer une DLL dans un répertoire et de l'exécuter dans un service Windows. J'ai trouvé que cela permettait d'éviter certaines des tâches gênantes liées au travail avec un service Windows et de nettoyer certaines parties de l'api Quartz.NET. Les services exécutés par DaemonMaster sont de deux types différents. Les premiers sont les travaux devant être exécutés toutes les nuits ou toutes les X minutes. Les autres travaux sont exécutés hors d'une file d'attente en fonction des données provenant de l'application ASP.NET. L'application ASP.NET place les objets JSON sur RabbitMQ et les services interrogent RabbitMQ, puis traitent les données.
Sur cette base, je vous suggérerais d’utiliser un service Windows (et de consulter DaemonMaster) et, si nécessaire, d’utiliser une file d’attente comme RabbitMQ pour la transmission des données de l’application ASP.NET aux services. C’est le meilleur de toutes ces solutions. . Si vous chargez le cache, alors exécuter ASP.NET est logique, sinon je ne le pense pas.
la source
Je le ferais de la bonne façon et j'aurais un service Windows en cours d'exécution qui surveille une "file d'attente". Je dis "file" car la programmation avec MSMQ s'apparente à coller des pokers chauds dans vos globes oculaires.
Je suis tombé amoureux de la simplicité de Delayed :: Job in Rails, et il est très facile de faire quelque chose de similaire dans .NET.
Fondamentalement, vous ajoutez une sorte de
SomethingOperation
(quelque chose qui a unePerform()
méthode). Ensuite, il suffit de sérialiser les paramètres pertinents, de lui donner une priorité, une sorte de comportement de nouvelle tentative par défaut et de les insérer dans une base de données.Votre service ne ferait que surveiller cela et traiter les travaux en file d'attente.
la source
Nous avons été plutôt satisfaits d’une approche Service Bus / Message Queue / Service. L'architecture de base est la suivante.
Le site Web envoie un message à la file d'attente
Le service Windows reçoit et traite le message en temps voulu
L'avantage est qu'il n'y a pas de délai pour le service frontal auquel les utilisateurs sont également connectés. Le service Windows peut être arrêté et mis à niveau sans interruption du site principal. De plus, c'est extrêmement rapide .
Si vous ne pouvez pas stocker toutes vos données dans le message, vous pouvez toujours les stocker et les récupérer ultérieurement. Je suggère d'utiliser un mécanisme de stockage de documents tel que: RavenDB ou MongoDB où il est très simple de stocker vos classes sans modification.
Le site Web envoie un message à la file d'attente
Le service Windows reçoit et traite le message en temps voulu
Pour simplifier les choses, nous utilisons Rhino ESB et Topshelf . La configuration est extrêmement simple et sa mise en place pour une application existante s’est avérée prendre très peu de temps.
la source
Je suis curieux de savoir pourquoi une combinaison des deux n'est pas une option viable. En ce moment, vous déclenchez des travaux sur les pages vues, avec un peu de chance malchanceux bloqué qui attend 10 secondes pour que la page apparaisse. Au moins c'est ce que je comprends de votre méthode actuelle.
Cependant, l'exécution de ces tâches prend de plus en plus de temps à mesure que le site se développe et vous ne voulez pas nuire à l'expérience utilisateur sur le site. Pas même pour quelques (ou peut-être beaucoup) utilisateurs malchanceux tout au long de la journée, vous envisagez donc maintenant de planifier des tâches en arrière-plan.
Je ne vois pas pourquoi un travail d'arrière-plan exécuté à intervalles réguliers ne peut pas imiter un visiteur. Maintenant, je ne suis pas un programmeur Windows, mais dans le monde Linux, je mettrais en place un travail cron qui s'exécute à un intervalle régulier et qui aurait 2 lignes de code.
Il combine les avantages des deux systèmes. C'est fait en arrière-plan. Cela n'affecte pas les utilisateurs. Il utilise toujours une page pour lancer le travail. J'ai déjà vu cette approche utilisée auparavant. Cela tend à être le juste milieu entre les manières simples d’ancien et les voies les plus complexes à venir.
Mise à jour
Je pense que vous pouvez contourner le problème de l'équilibrage de la charge en exécutant les coureurs de travaux sur les serveurs Web eux-mêmes. Le lanceur de travaux extrait une URL de la file d'attente et l'exécute comme suit:
En raison de la nature des files d'attente de travail / de messagerie, les travaux seront répartis de manière égale entre les coureurs de travaux, ce qui signifie que la propriété special_crafted_url sera éventuellement distribuée sur vos serveurs Web.
la source
specially_crafted_url
provient d'une adresse IP connue, vous pouvez ajouter une règle à votre équilibreur de charge pour effectuer un round-robin uniquement pour les demandes provenant de cette adresse IP.Je pense que le problème avec l'approche purement axée sur le service est que le code est dispersé dans le service et éloigné de l'application principale.
Voici ce que nous avons fait avec des tâches d'arrière-plan de grande taille, non sensibles au facteur temps, qui permettent de conserver le code ensemble et de simplifier le service:
Encore plus simple, il suffit de faire l'appel dans une application console et d'utiliser le Planificateur de tâches ou VisualCron pour en faire un "service".
la source
J'ai aimé TopShelf. Conserve la simplicité, tout en conservant le bon fonctionnement en tant que service Windows. Fondamentalement, créez une application console, ajoutez environ 15 à 20 lignes de code, puis installez-la en tant que service.
http://code.google.com/p/topshelf/
la source
Que diriez-vous d’un service Windows très simple qui s’exécute sur le serveur Web et affiche périodiquement une URL de maintenance qui effectue vos tâches diverses. Demandez-lui de limiter le travail qu’il accomplit dans une demande donnée.
la source
Je vais inverser la tendance apparente ici et suggérer de choisir le modèle in-IIS. Je l'ai utilisé moi-même et cela fonctionne vraiment bien. Il n'est vraiment pas difficile d'implémenter une classe de pool de threads décente (au fil des années, j'ai élargi ma classe de pool de threads pour prendre en charge la création et la destruction dynamiques de threads, la nouvelle tentative de travaux, etc.). Les avantages sont:
À mon avis, une solution in-IIS est tout simplement la "prochaine étape" en combinant le travail à des vues de page aléatoires.
la source
Resque est sympa. Ou même Kthxbye si vous devez être informé de la valeur obtenue une fois celle-ci complétée.
Tous deux basés à Redis / Ruby.
Honnêtement, si vous utilisez une approche basée sur les services, elle n’a pas vraiment besoin d’être super intégrée à votre plateforme actuelle, ce qui, à mon avis, est un avantage. J'espère que ce sera un système paramétrable qui fonctionnerait (avec une sorte de surveillance) et achèverait des travaux. Je ne suis pas sûr qu'il doive être exécuté sur la même plate-forme, car il ne fait que mettre à jour / modifier les informations de la base de données.
Je suis presque sûr que vous pourriez obtenir beaucoup plus pour beaucoup moins si vous exploitiez ce type de travail, mais plutôt parce que vous avez affaire à des problèmes de filetage. Les deux Resque et kthxbye déplacer le traitement vers des processus séparés pour permettre le système d' exploitation pour gérer la concurrence.
Resque
Kthxbye
la source
J'utiliserais un service WCF hébergé par WAS en écoutant une file d'attente MSMQ.
Avantages
Feu et oublie les messages à sens unique de l'application Web
MSMQ / WCF étranglement et réessayez
Livraison garantie; D
Lettre morte gestion
Traitement distribué
Activation WAS / MSMQ
Les inconvénients
Les fonctionnalités MSMQ dans WCF rendent l'utilisation de MSMQ vraiment agréable. Oui, vous saurez sur la configuration, mais les avantages l'emporteront sur les sacrifices.
la source
Je l'ai rencontré à quelques reprises lors du développement d'applications Web. Nous avons résolu ce problème en créant une application console Windows qui exécute la tâche et en créant une tâche planifiée qui s'exécute de temps en temps pour effectuer la tâche.
la source
Vous pouvez shunter un travail sur un fil d’arrière-plan (ou sur plusieurs fils d’arrière-plan) à l’aide de Rx et de l’apparence suivante:
Utiliser:
Hébergez tout cela dans une classe dont il n’existe qu’un seul (alias un singleton, mais faites-le correctement - utilisez votre conteneur IoC pour déterminer le mode de vie).
Vous pouvez contrôler la taille du pool de threads, etc. en écrivant un planificateur personnalisé au lieu d'utiliser EventLoopScheduler (qui exécute un seul thread).
la source
J'ai implémenté ce genre de chose à quelques reprises. Sur Windows, j'ai mis en place un programme en ligne de commande Python qui fait quelque chose à différents moments. Ce programme expose également une interface xmlrpc sur un port. Ensuite, un travail de tâche planifiée est exécuté toutes les minutes et interroge les interfaces xmlrpc. S'ils ne sont pas levés, il essaie de les lancer. S'il ne peut pas, il m'envoie un email.
L'avantage est que le travail qui s'exécute n'est pas lié à la charge ou à la planification. J'ai un travail de processus qui s'exécute toutes les secondes, mais j'attendrai de plus en plus longtemps avant de commencer un nouveau travail en fonction de la tâche à accomplir. En outre, il peut être utilisé pour agir intelligemment en fonction du résultat. Vous avez une erreur 500? Vous avez un très long délai? Fais autre chose. Notifier un autre service. Etc.
Et le même système fonctionne sous unix, avec des modifications mineures.
la source
Je n'ai pas de réponse pour vous moi-même, mais le problème a sonné une cloche - je me souviens que des gars au hasard en ont discuté une fois sur un podcast .
la source
Vue d'ensemble de l'API Java de la file d'attente de tâches
Concepts de tâche
Dans le traitement en arrière-plan d'App Engine, une tâche est une description complète d'une petite unité de travail. Cette description comprend deux parties:
Les tâches en tant que crochets Web hors
connexion Heureusement, Internet fournit déjà une telle solution, sous la forme d'une requête HTTP et de sa réponse. La charge de données correspond au contenu de la demande HTTP, tel que des variables de formulaire Web, XML, JSON ou des données binaires codées. La référence de code est l'URL elle-même; le code réel correspond à la logique que le serveur exécute pour préparer la réponse.
la source
Faire les deux
Ajoutez un paramètre facultatif au chemin de la question qui effectue le travail que vous suivez actuellement sur les demandes des utilisateurs:
Gestion des tâches en arrière-plan sur un grand site
Créez une application de console qui s'exécute sur chaque serveur et ouvre le binaire partagé du journal IIS et le lit à la fin du fichier. Utilisez un système de fichiers ou un intervalle chronométré pour lire en avant afin de collecter les mises à jour lorsque IIS a vidé le journal.
Utilisez ces informations pour déterminer quelles pages ont été consultées.
Utilisez les URL de page du journal analysé pour appeler la version "extrastuff" de l’URL sur localhost avec un objet webclient.
Ajoutez du code pour changer de fichier à la fin de chaque période de journal ou redémarrez le processus à chaque période de journal.
la source