4

I have a windows service that reads my message queue through WCF. I want the service to process one message before another message (intensive memory actions per msg). I set the throttling configuration to 1, but it does not seem to do anything. If i have 6 messages in my queue, it takes 4 right after the start.

Am i missing something?

My web.config :

  <system.serviceModel>
<client>
  <endpoint
    address="net.tcp://spserv30:9999/services/SPInterface"
    binding="netTcpBinding" bindingConfiguration="tcpspbinding"
    contract="Itineris.OPM.WCFSP.ActionContracts.ISPActions" >
  </endpoint>
</client>
<services>
  <service name="Itineris.OPM.MSMQProcessorV2.MSMQProcessor" behaviorConfiguration="Throttled" >
    <endpoint address="msmq.formatname:DIRECT=OS:localhost\private$\documents" binding="msmqIntegrationBinding"
              bindingConfiguration="MSMQProcessorBinding" contract="Itineris.OPM.MSMQProcessorV2.IMSMQProcessor" />
  </service>
</services>
<bindings>
  <netTcpBinding>
    <binding name="tcpspbinding" transferMode="StreamedRequest" />
  </netTcpBinding>
  <msmqIntegrationBinding>
    <binding name="MSMQProcessorBinding" maxReceivedMessageSize="2147483647" 
             receiveRetryCount="0" retryCycleDelay="00:10:00" maxRetryCycles="0"
             receiveErrorHandling="Move">
      <security mode="None" />
    </binding>
  </msmqIntegrationBinding>


   </bindings>
 <behaviors>
      <serviceBehaviors>
        <behavior name="Throttled">
          <serviceThrottling 
            maxConcurrentCalls="1" 
            maxConcurrentSessions="1" 
            maxConcurrentInstances="1"
          />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

My servicehost creation :

  protected override void OnStart(string[] args)
    {

            if (_serviceHost != null)
            {
                if (_serviceHost.State != CommunicationState.Faulted)
                    _serviceHost.Close();
                else
                    _serviceHost.Abort();
            }
            //create servicehost
            _serviceHost = new ServiceHost(typeof(MSMQProcessor));
            _serviceHost.Open();
            _serviceHost.Faulted += serviceHost_Faulted;

            // Already load configuration here so that service does not start if there is a configuration error.
            new DocumentGeneratorV2.LoadGeneratorConfigurator().Load();

            var startLog = new LogEntry {Message = "Itineris MSMQ Processor Service V2 has started"};
            startLog.Categories.Add(CategoryGeneral);
            startLog.Priority = PriorityNormal;

            Logger.Write(startLog);






    }

    private void serviceHost_Faulted(object sender, EventArgs e)
    {
        if (!_isClosing)
        {
            _serviceHost.Abort();
            _serviceHost = new ServiceHost(typeof(MSMQProcessor));
            _serviceHost.Faulted += serviceHost_Faulted;
            _serviceHost.Open();
        }
    }

Class with contract :

  [ServiceContract(Namespace = "http://Itineris.DocxGenerator.MSMQProcessor")]
[ServiceKnownType(typeof(string))]
public interface IMSMQProcessor

{
    [OperationContract(IsOneWay = true, Action = "*")]
    void GenerateWordDocument(MsmqMessage<string> message);
}

public class MSMQProcessor : IMSMQProcessor
{
    /// <summary>
    /// Method that processed the message and generates a word document
    /// </summary>
    /// <param name="message">message from MSMQ to be processed</param>
    [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
    public void GenerateWordDocument(MsmqMessage<string> message)
    {
        DocumentGeneration documentGenerator = null;
        var state = new DocumentStatus();
        var docGenerator = new DocumentGenerator(new LoadGeneratorConfigurator().Load());


            var deserializer = new XmlSerializer(typeof(DocumentGeneration));

            documentGenerator = deserializer.Deserialize(new StringReader(message.Body)) as DocumentGeneration;
            if(documentGenerator == null)
                throw new Exception("Deserializing of the message has failed");

            docGenerator.MailQueue = appSettings["MAILQUEUE"];
            docGenerator.GenerateDocument(documentGenerator);


            var builder = new StringBuilder();
            builder.Append("The documents have been saved to the following locations: \r\n");

            }
            }
Sixto Saez
  • 12,610
  • 5
  • 43
  • 51
Rogue101
  • 115
  • 1
  • 9
  • You haven't put some key information about your service configuration into the question: what does the ServiceBehavior attribute for the service implementation class contain & what does the serviceModel>behaviors>serviceBehavior element named "Throttled" contain. Can't really suggest any thing without that information. – Sixto Saez May 24 '11 at 15:30
  • Sorry on the "Throttled" section, must of have had a stale copy of the question. The ServiceBehavior attribute for the implementation class is still needed though. – Sixto Saez May 24 '11 at 15:48
  • I've added my implementation class, sorry for the missing piece. Is it necessary to specify servicebehavior in the class when it is specified in the config? – Rogue101 May 25 '11 at 07:16
  • It isn't required if you're OK with the default values it provides. I just wanted to make sure you hadn't set ConcurrencyMode to Multiple in your code. – Sixto Saez May 25 '11 at 13:24

1 Answers1

3

Your service as configured in the question should only process message at a time. Although you are not using the ServiceBehavior attribute for the service implementation class, the default value for the ConcurrencyMode is Single not Multiple (which could cause the behavior you are seeing). The default value of InstanceContextMode is Per Session but the maxConcurrentInstances and maxConcurrentSessions values force support for a single session at a time.

The only other option that I see is to force the ServiceHost to use only one service instance by using a different constructor. Here is the code:

// ... snipped ...

//force single service instance to be used by servicehost
var singleton = new MSMQProcessor();
_serviceHost = new ServiceHost(singleton);
_serviceHost.Open();


// ... snipped ...
Sixto Saez
  • 12,610
  • 5
  • 43
  • 51
  • I got it working with above option and configuring it on my methods, instead of using the config file. Thanks for the help! – Rogue101 Jun 07 '11 at 07:42