Que se passe-t-il lorsque le temps de traitement sur un serveur dépasse le rythme d'envoi par les clients ? Si le rythme moyen dépasse la capacité de traitement, il faut un plus gros serveur, mais 9 fois sur 10 c'est le rythme en pic qui pose problème. Microsoft fournit une solution depuis NT4 : Message Queue Server (ou MSMQ), un serveur de messagerie applicative.
Si MSMQ est installé sur votre serveur, et que la communication entre les clients et le serveur est faite en WCF, vous pouvez très simplement vous appuyer sur MSMQ pour absorber les pics de charge.
Pour fixer les idées, imaginez le problème suivant : Votre serveur permet d'envoyer des SMS, mais il est limité à un message/seconde. Vos clients envoient le matin des vagues de SMS. Qu'un SMS mette 15 minutes à parvenir à destination n'est pas dramatique, mais il est impératif que chaque SMS soit transmis à son destinataire.
En termes techniques, le serveur expose le contrat de service suivant :
[ServiceContract]
interface ICommunicationsDiverses
{
[OperationContract (IsOneWay=true) ]
void EnvoieSMS(string numero, string sms);
}
Puisque nous allons stocker les demandes d'exécution en file d'attente, l'opération d'envoi de SMS ne peut pas renvoyer directement de message, il faut donc une signature void dans l'implémentation et un attribut IsOneWay dans le contrat.
La communication met maintenant en jeu trois acteurs : les clients, le serveur, et la file d'attente qui s'intercale entre les deux. Cette dernière doit être déclarée sur le poste serveur.
La suite est un simple travail de configuration, consistant à préciser aux clients et au serveur qu'ils doivent passer par la file d'attente pour se passer les messages :
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<netMsmqBinding>
<binding name="monBindingMSMQ">
<security mode="None">
<transport msmqAuthenticationMode="None" msmqProtectionLevel="None" />
<message clientCredentialType="None" />
</security>
</binding>
</netMsmqBinding>
</bindings>
<client>
<endpoint
name="nomDuEndPoint"
address="net.msmq://localhost/Private/MaFile"
binding="netMsmqBinding"
contract="ICommunicationsDiverses"
bindingConfiguration="monBindingMSMQ" >
</endpoint>
</client>
</system.serviceModel>
</configuration>
Et pour le serveur :
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<netMsmqBinding>
<binding name="monBindingMSMQ">
<security mode="None">
<transport msmqAuthenticationMode="None" msmqProtectionLevel="None" />
<message clientCredentialType="None" />
</security>
</binding>
</netMsmqBinding>
</bindings>
<services>
<service name="MonAppliSuperCompliquee.ClasseImplementantLInterface">
<endpoint address="net.msmq://localhost/Private/MaFile" binding="netMsmqBinding"
bindingConfiguration="monBindingMSMQ" name="nomEndPointServeur" contract="ICommunicationsDiverses" />
</service>
</services>
</system.serviceModel>
</configuration>
C'est tout. A partir de maintenant, les appels fonctionneront même si le serveur est arrêté, puisqu'ils sont stockés dans la file d'attente, et le serveur les traitera un à un quel que soit le nombre d'appels en attente.