Rhino ESB publish/subscribe backend - servicebus

I have 2 applications, Desktop app the clients use, Win Service that does the backend processing. I want to be able to trigger the backend processing via a message using Rhino Service Bus. This message may come from the client app, it may come from the win service, I don't really care who triggers it. So I need pub sub. The problem is that I can trigger it just fine from my console app, when I try to trigger from my service I get an error there are no subscribers for the message. What is wrong in my configs?
Console app.config
<rhino.esb>
<bus threadCount="1" numberOfRetries="5" endpoint="msmq://localhost/console.debug" />
<messages>
<add name="MyMessages" endpoint="msmq://localhost/host.debug" />
</messages>
Win Service app.config
<rhino.esb>
<bus threadCount="1" numberOfRetries="5" endpoint="msmq://localhost/host.debug" />
<messages />
The code for sending a message is the same in both apps:
private IServiceBus _serviceBus;
....
public void Trigger()
{
_serviceBus.Publish(new myTriggerCommand());
}

So it seems RSB is unable to handle publishing messages to itself. I found this blog for publishing and consuming in the same process, which appears to be a reasonable solution. However, in the end I opted just to not use messaging for triggering within the host.
http://blog.irm.se/blogs/eric/archive/2011/06/19/Consuming-Events-in-the-Same-Process-as-the-Publisher-with-Rhino-Service-Bus.aspx

Related

nservicebus unobtrusive mode not picking up handlers or processing messages

I am trying to put together a prototype using Nservicebus using the unobtrusive mode by defining custom conventions. I started trying to run my endpoint in the NServicebus host but had no luck with it picking up a message that I publish. I took the Unobtrusive sample application available from Nservicebus and replaced its contents with my messages and handlers. It appears to detect the messages based on convention (I see it in the console output when the app is running), but does not appear to register for those messages based on the handlers I have in the Server application. I don't see the message being put in the queue and I cannot see an active or inactive endpoint in service pulse either when the application is running.
I have tried many different "fixes" and have scoured the internet, stack overflow, and the Nservicebus documentation and have not found any information to point me in the right direction.
Here is my server endpoint config:
BusConfiguration busConfiguration = new BusConfiguration();
busConfiguration.EnableInstallers();
busConfiguration.UsePersistence<InMemoryPersistence>();
busConfiguration.UseDataBus<FileShareDataBus>()
.BasePath(#"..\..\..\DataBusShare\");
busConfiguration.RijndaelEncryptionService();
busConfiguration.ApplyCustomConventions();
using (IBus bus = Bus.Create(busConfiguration).Start())
{
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
public static void ApplyCustomConventions(this BusConfiguration busConfiguration)
{
ConventionsBuilder conventions = busConfiguration.Conventions();
conventions.DefiningCommandsAs(t => t.Namespace != null && t.Namespace.EndsWith("Commands"));
conventions.DefiningEventsAs(t => t.Namespace != null && t.Namespace.EndsWith("Events"));
conventions.DefiningMessagesAs(t => t.Namespace != null && t.Namespace == "Messages");
conventions.DefiningEncryptedPropertiesAs(p => p.Name.StartsWith("Encrypted"));
//conventions.DefiningDataBusPropertiesAs(p => p.Name.EndsWith("DataBus"));
conventions.DefiningExpressMessagesAs(t => t.Name.EndsWith("Express"));
conventions
.DefiningTimeToBeReceivedAs(t => t.Name.EndsWith("Expires")
? TimeSpan.FromSeconds(30)
: TimeSpan.MaxValue
);
}
The ApplyCustomConventions method is shared between my message publisher and the Server endpoint.
Here is my Server endpoint .exe app.config:
<configuration>
<configSections>
<section name="RijndaelEncryptionServiceConfig" type="NServiceBus.Config.RijndaelEncryptionServiceConfig, NServiceBus.Core"/>
</configSections>
<RijndaelEncryptionServiceConfig Key="gdDbqRpqdRbTs3mhdZh8qCaDaxJXl+e7"/>
</configuration>
There is no error on publish and the message is never received.
Update: I have narrowed this down to it not working when i try to publish events and the endpoint will not subscribe unless I do an endpoint mapping. Furthermore, even after I publish an event with the endpoint mapping in place it is still not picked up by my endpoint handlers.
I have a questions here. In the unobtrusive example from Particular it does not set up any endpoint mappings to be able to send commands and messages, it sets up a endpoint based on the assembly name. Does this not work with events and publish? I took the unobtrusive example and put one event message in Messages.dll, and added one handler for that event in the Server.exe, and changed the Client.exe to be able to publish that event and it does not work.
I will try to post my code somewhere when i get a chance. Thanks guys.
When running an endpoint with unobtrusive mode, make sure you are doing the definitions in both the sender and receiver.
Also, post some of your endpoint configuration code here, that might help troubleshooting.
Do you get any errors when doing the send at the receiving endpoint? Much of the time some type of error is thrown that can help troubleshoot this.
I noticed that in your app.config you do not have the endpoint mappings defined. This is needed on both the "frontend" and "backend" projects to route the messages to right spot. Here is a snippet of what mine is for an application called "myapplication":
<UnicastBusConfig>
<MessageEndpointMappings>
<add Messages="myapplication.Commands" Endpoint="myapplication.Backend" />
</MessageEndpointMappings>
</UnicastBusConfig>
More information about this can be found here: http://docs.particular.net/nservicebus/messaging/specify-message-destination
Both endpoints will require the unobtrusive mappings. The subscriber endpoint should be configured to subscribe to the messages. See here for how to configure the subscriber:
http://docs.particular.net/nservicebus/messaging/publish-subscribe/configuration
The App.config will looks something like this for your subscriber:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="UnicastBusConfig" type="NServiceBus.Config.UnicastBusConfig, NServiceBus.Core"/>
</configSections>
<UnicastBusConfig>
<MessageEndpointMappings>
<add Assembly="Shared" Endpoint="Samples.PubSub.MyPublisher"/>
</MessageEndpointMappings>
</UnicastBusConfig>
</configuration>

Nservicebus disable default logger in web.config

I'm using the DefaultFactory LogManager for Nservicebus v5. I'm happy with this but was hoping to be able to disable via the web.config.
I use web.config settings, as found in the help docs
<configSections>
<section name="Logging" type="NServiceBus.Config.Logging, NServiceBus.Core" />
</configSections>
<Logging Threshold="Debug" />
I'd prefer not to set the threshold as fatal. I was hoping for a "None" or Disabled="true"
Also can the directory path be set web.config?
Update: Why would we want to ignore errors?
The short is we don't really have write permission on the servers.
The long is this isn't 100% true.
Our systems is moving towards microservices, the problem with this is that decentralized logging is a tracing/visualization nightmare.
So we moved flow tracing, exceptions, and limited tracing to a centralized system.
Programming Entry points (aka message Handlers, web api endpoints, etc) are nearly always wrapped in a try catch log throw on each handler, this covers all our programming errors. This isn't anything really that different to normal.
The centralized logging location sets of all the nice red flashing real time alarms one could wish for.
Which leaves only configuration type error left like missing queues, bad assembly bindings, faulty config files, or more runtime style stuff like IoC wiring (outside of the handler code).
With the centralized logging and monitoring of the error quests, it is fairly easy to detect when the service is broken and if it is then we turn on logging, restart, try the faulty issue, and fix.
Guaranteed delivery will take care of everything else once it is up again :D Gone are the days of 150mb log files spread across 10 different servers.
The simplicity of DefaultFactory was nice, as was not needing another nuget package and associated configuration.
Is this the correct way forward. Many would argue no.
Could we have done it better? yes we could implement the common logger interface and pass it into NServiceBus but we arn't quiet there just yet and the win isn't critical atm.
A side note: One really really nice thing about the way we log is that in our backoffice tool we have been able to simply show the flow for each "order", similar to using a correlation id in greylog.
Since this was not considered a likely scenario it does not have a first class API. But you can achieve this via passing in a null logger from any of the common logging libraries (NLog, Log4net, CommonLogging). I assume you are using one of these in your website.
So take NLog for example.
Install-Package NServiceBus.NLog
The in your webconfig
<appSettings>
<add key="disableLogging" value="true"/>
</appSettings>
Then in your global startup
if (ConfigurationManager.AppSettings.Get("disableLogging") == "true")
{
LoggingConfiguration config = new LoggingConfiguration();
LogManager.Configuration = config;
NServiceBus.Logging.LogManager.Use<NLogFactory>();
}
This is leveraging the approach documented here http://docs.particular.net/nservicebus/logging-in-nservicebus#nlog

Can't get service to pull from (dead letter) queue

I have a queue named log on a remote machine. When I call that queue locally, I specify a custom dead-letter queue by modifying my NetMsmqBinding:
_binding.DeadLetterQueue = DeadLetterQueue.Custom;
_binding.CustomDeadLetterQueue = new Uri(
"net.msmq://localhost/private/Services/Logging/LogDeadLetterService.svc");
This works fine; when I force my message to fail to get to its destination, it appears in this queue.
Now, I have a service hosted in IIS/WAS to read the dead-letter queue. It it hosted in a site called Services, at Services/Logging/LogDeadLetterService.svc. Here's the service in my config:
<service name="Me.Logging.Service.LoggingDeadLetterService">
<endpoint binding="netMsmqBinding"
bindingNamespace="http://me.logging/services/2012/11"
contract="Me.Logging.Service.Shared.Service.Contracts.ILog" />
</service>
And here's my activation:
<add relativeAddress="LogDeadLetterService.svc"
service="Me.Logging.Service.LoggingDeadLetterService" />
My actual service is basically this:
[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any, // Pick up any messages, regardless of To address.
InstanceContextMode = InstanceContextMode.Single, // Singleton instance of this class.
ConcurrencyMode = ConcurrencyMode.Multiple, // Multiple callers at a time.
Namespace = "http://me.logging/services/2012/11")]
public class LoggingDeadLetterService : ILog
{
public void LogApplication(ApplicationLog entry)
{
LogToEventLog(entry);
}
}
My queue is transactional and authenticated. I have net.msmq included as enabled protocols both on the Services site and on the Logging application, and I added a net.msmq binding to the Services site. If I have the binding information as appdev.me.com, I get the following error when browsing to http://appdev.me.com/Logging/LogDeadLetterService.svc (appdev.me.com is setup in my HOSTS file):
An error occurred while opening the queue:Access is denied. (-1072824283, 0xc00e0025).
If I have the binding information as localhost, I get the following error:
An error occurred while opening the queue:The queue does not exist or you do not have sufficient permissions to perform the operation. (-1072824317, 0xc00e0003).
No matter which way I have it set up, the service isn't picking up the dead letter, as it's still in the queue and not in my event log.
Now, I realize that both of these reference a permissions issue. However, in the interest of getting the code part of this tested before figuring out the authentication piece, I have given Full Control to everyone I could think of - to include Everyone, Authenticated Users, NETWORK SERVICE, IIS_USERS, ANONYMOUS LOGON, and myself. (The app pool is running as me.)
Any help as to how to get my service to be able to pull from this queue would be phenomenal. Thanks!
EDIT: According to this MSDN blog entry, 0xC00E0003 corresponds to MQ_ERROR_QUEUE_NOT_FOUND, and 0xc00e0025 corresponds to MQ_ERROR_ACCESS_DENIED, so it looks like I want to have the binding information as appdev.me.com. However, that still doesn't resolve the apparent permissions issue occurring.
EDIT2: It works if I host the service in a console app and provide the following endpoint:
<endpoint address="net.msmq://localhost/private/Services/Logging/LogDeadLetterService.svc"
binding="netMsmqBinding"
bindingNamespace="http://me.logging/services/2012/11"
contract="Me.Logging.Service.Shared.Service.Contracts.ILog" />
So what's going on differently in the console app than is going on in IIS? I'm pretty confident, due to EDIT above, that I'm hitting the queue. So why can't I get into it?
EDIT3: Changed Services/Logging/LogDeadLetterService.svc to Logging/LogDeadLetterService.svc per the advice given here, but no change.
//
[Bonus question: Do I need to handle poison messages in my dead letter queue?]
So, three things needed to be changed:
The binding does have to be localhost.
The queue has to be named Logging/LogDeadLetterService.svc to be found - it's the application and the service, not the site, application, and service.
I had something messed up with the application pool - I have no idea what it was, but using a different app pool worked, so I backed out all of my service-related changes and then recreated everything, and it works.
Well, that was a lot of banging my head against my desk for something as simple as "don't mess up your app pool."

WCF Service cannot be opened - too many client calls

I have a WCF Web Service hosted in a Windows Service.
The service is configured using the following attributes (VB)
<ServiceBehavior(ConcurrencyMode:=ConcurrencyMode.Multiple,
InstanceContextMode:=InstanceContextMode.PerCall,
UseSynchronizationContext:=False)>
I created a test client, which creates 50 threads at once and and I am starting them straight away, all querying an operation on the WCF Service. The first 30 or so openings (client.open()) work, but afterwards I get an error message on my client that the opening couldn't be done because there was a timeout while trying to open the service and thus I get an EndPointNotFoundException. (The operationss I am calling are all synchronous if that matters.)
Can I expect that sort of behaviour and thus simply have to live with these exceptions or do I have to look at some of my settings, either the above, or any other settings? (I am using a NetTcpBinding.)
What I see is that the client works on the request of the at once created threads simultaneously, so the above settings have the desired effect of making the service multi-user-at-the-same-time-enabled.
But ideally I wouldn't get timeout exceptions. Rather I would want the clients to wait longer to get their response than to time out.
Any ideas?
Thanks all!
Check settings such as these:
<behavior name="CommonServices_Behavior">
<serviceThrottling maxConcurrentCalls="100" maxConcurrentSessions="50"
maxConcurrentInstances="50" />
</behavior>
I seem to recall that some of these values have defaults set in your machine.config file. There is also a MaxConnections value to check for NetTcpBinding.

WCF service inside an MVC-app that uses msmqIntegrationBinding does not receive messages from msmq

I have a MVC-app that has a controller with an action that is supposed to expose data from the latest message in a queue (msmq). I have added a private queue on my local machine. I want the application to automatically receive a message from the queue when one is added. For this i am using msmqIntegrationBinding on a WCF-service that has been added to the application. The method that takes the message in the contract i then supposed to save the message in the application cache so that it can be accessed when a client asks for the latest data.
The challenge I now face is that when I add a message to the queue, it's not being picked up by the WCF-service. I need guidance at what I might be doing wrong or feedback on my approach. Please help.
The following is the endpoint-config for the WCF-service:
<bindings>
<msmqIntegrationBinding>
<binding name="MsmqBinding">
<security mode="None" />
</binding>
</msmqIntegrationBinding>
</bindings>
<services>
<service name="TestApp.Web.Service.QueueMessageReceiver">
<endpoint address="msmq.formatname:DIRECT=OS:.\private$\testsmessagequeue"
binding="msmqIntegrationBinding"
bindingConfiguration="MsmqBinding"
contract="TestApp.Web.Service.IQueueMessageReceiver" />
</service>
</services>
And the following code is from the QueueMessageReceiver.cs WCF-service:
public class QueueMessageReceiver : IQueueMessageReceiver
{
private static readonly XmlSerializer Serializer = new XmlSerializer(typeof(ScrewInfoModel));
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void PutScrewInfoMessage(System.ServiceModel.MsmqIntegration.MsmqMessage<System.Xml.XmlDocument> msg)
{
CacheScrewInfoModelFromScrewInfoXmlDoc(msg.Body);
}
private static void CacheScrewInfoModelFromScrewInfoXmlDoc(XmlNode screwInfoXmlDoc)
{
var reader = new StringReader(screwInfoXmlDoc.InnerXml);
var screwInfoModel = (ScrewInfoModel)Serializer.Deserialize(reader);
Common.Utils.CacheScrewInfo(screwInfoModel);
}
}
And here is the Interface for the WCF:
[ServiceContract]
public interface IQueueMessageReceiver
{
[OperationContract(IsOneWay = true, Action = "*")]
void PutScrewInfoMessage(MsmqMessage<XmlDocument> msg);
}
Try changing your operation contract to
void PutScrewInfoMessage(MsmqMessage<string> msg);
It's possible that the WCF stack is having difficulty with the deserialization to XmlDocument.
UPDATE
Things to try:
Make suer your queue "testsmessagequeue" have the correct permissions set. In this case the service account running the app pool hosting your controller needs to have the "Receive Message" permissions set.
Enable MSMQ logging (if you're on windows 2008 server or windows 7 and above) which can be found in Event Viewer under: Applications and Services Logs -> Microsoft -> Windows -> MSMQ -> End2End. This will capture everything that happens in MSMQ including any errors.
Try making the queue transactional (if it not already). This will ensure that an error condition will exist on message non-delivery.
Enable WCF tracing on your service endpoint to see any specific WCF errors happening with the dequeuing of the message.
UPDATE 2
I think the problem is queue permissions. Your app pool is running under the user ApplicationPoolIdentity (if it's running under the .net 4.0 app pool). The user which corresponds to this identity is called DefaultAppPool. You need to give this user receive message permissions on the queue. To select this user search for a local account called IIS AppPool\DefaultAppPool in the Select Users dialogue.
UPDATE 3
It just struck me that IIS is not an appropriate hosting container for a queue listener. The reason for this is that the app pool unloads after a period of inactivity. This is controlled by IIS and is not configurable. (see here)
I think you should create a new hosting container in a windows service (you can use a console host to spike this) to host the queue endpoint. The windows service will run under an actual service account so granting permissions will be less complicated.
This service can write either write directly into the cache, or if this is not possible, should write to a DB where the website controller can refresh the cache from.
Does this make sense?
UPDATE 4
Poison message means that the message cannot be dequeued because of some problem with it. Check the system queue called Transactional Dead Letter Queue and see if your message is in there.