How does MessageEndpointMappings know to setup a subscription vs outgoing messages? - nservicebus

I see MessageEndpointMappings section in my App.config and it just keeps confusing me.
Sometimes it looks like it sets of a client to subscribe to another queue (like this one does):
<UnicastBusConfig>
<MessageEndpointMappings>
<add Messages="MyServiceBus.MessageHub.Contracts" Endpoint="MessageHub"/>
</MessageEndpointMappings>
</UnicastBusConfig>
But other times it seems to be used to configure outgoing messages to other queues:
<UnicastBusConfig>
<MessageEndpointMappings>
<add Messages="ServiceBus.MessageHub.InternalMessages" Endpoint="MessageHub"/>
</MessageEndpointMappings>
</UnicastBusConfig>
But really, there is no difference between the two of them. So how does it know when to setup a subscription and when to setup for sending messages?
Or is it really doing both all the time and I just don't use both?

Essentially, what you're declaring with the MessageEndpointMappings element, is "who is the owner of the specified messages?"
Another way to view it, is that this is the direction of the service dependency - not the message flow, because that is determined by whether messages get Sendt or Publishd.
Therefore, in order to be able to send messages and subscribe to messages from a given service, you declare an endpoint mapping in the sender/subscriber end.
And then, when the sender/subscriber has an endpoint mapping that points to another service and a handler for a message included in that endpoint mapping, NServiceBus is nice enough to automatically subscribe to that message (unless you disable the auto-subscription with DoNotAutoSubscribe()) - because, logically, that must mean that the sender/subscriber wishes to subscribe to the given message.
When you think about it this way, I think it makes sense. Hope you feel so too :)

Related

Clarification of topology

I understand that Rebus is perfectly capable of transporting messages from point A to B (using MSMQ as the transport layer). To make things perfectly clear, is Rebus also capable of doing one-to-many messaging, i.e. messages sent from point A should end at both point B and C?
And if it is possible, how does it do it? I cannot see any centralised distribution site (a post-office), so I assume that the communication will consist of a channel from every endpoint to every other endpoint (so that in a network where a process has to communicate with 5 other endpoints, there will be 5 channels radiating out of this process). Can you confirm this assumption?
Yes, Rebus is indeed capable of publishing messages to virtually any number of subscribers. It's true that MSMQ (at least in its most basic mode of operation) is a simple point-to-point channel, which is why there's a layer on top in order to implement true pub/sub.
The way it works, is that each subscriber has an endpoint mapping pointing to the publisher, and then each subscriber goes
bus.Subsribe<SomethingInterestingHappened>();
which causes an internal SubscriptionMessage to be sent the the publisher. The publisher must then remember who subscribed to each given message type, typically by storing this information in an SQL Server. All this happens automatically, it just requires that you configure some kind of subscription storage.
And then, when the time comes to publish something, the publisher goes
bus.Publish(new SomethingInterestingHappened { ... });
which will make Rebus look up all the subscribers of the given message type. This may be 0, 1 or more, and then the event will be sent to each subscriber's input queue.
You can read more about these things in the Rebus docs on the page about routing.
To give you a hint on how subscribers and publishers might be configured, check this out - this is a subscriber:
Configure.With(...)
.Transport(t => t.UseMsmq....)
.MessageOwnership(t => t.FromRebusConfigurationSection())
(...)
which also has an endpoint mapping that maps a bunch of events to a specific publisher:
<endpoints>
<add messages="SomePublisher.Messages" endpoint="publisher_input_queue" />
</endpoint>
and then the publisher might look like this:
Configure.With(...)
.Transport(t => t.UseMsmq....)
.Subscriptions(s => s.StoreInSqlServer(theConnectionString, "subscriptions")
.EnsureTableIsCreated())
(...)

WCF duplex channel, de-coupling the request and the response

I'm contemplating a project where I'll be required to make use of what is variously called the "asynchronous" mode, or the "duplex" mode, or the "callback" mode of SOAP webservice. In this mode, the caller of the service provides in the SOAP header a "reply-to" address, and the service, instead of returning the output of the call in the HTTP response, creates a separate HTTP connection to this "reply-to" address and posts the response message to it. This is normally achieved in WCF using a CompositeDuplexBinding, like so:
<binding name="async_http_text">
<compositeDuplex clientBaseAddress="http://192.168.10.123:1234/async" />
<oneWay />
<textMessageEncoding messageVersion="Soap12WSAddressing10" />
<httpTransport useDefaultWebProxy="false" />
</binding>
This results in not one, but two HTTP connections per call: one from the client to the service, and then one from the service back to the client. From the point of view of the service implementation, nothing changes, you have a method that implements the interface method, and you take in the request and return the response. Fantastic, this is what I need, almost.
In my situation, the request and response can be separated by anything from minutes to days. I need a way to decouple the request and the response, and "store" the state (message, response URI, whatever) until I have enough information to respond at a later time (or even never, under certain circumstances).
I'm not terribly excited about having my methods essentially "paused" for up to days at a time, along with the required silly timeout values (if they're even accepted as valid), but I don't know how to go about putting a system like this together.
In order to be completely clear, I'm implementing a set of standards provided by a standards body, so I do not have flexibility to change SOAP message semantics or alter protocol implementations. This sort of interaction is exactly what was intended when the ReplyTo header was implemented in WS-Addressing.
How would you do it? Perhaps Workflow Foundation enables this sort of thing?
In such case don't use HTTP duplex communication as defined in WCF. It will simply not work because it is dependent on some other prerequisities - session, service instance living on the server, etc. It all adds a lot of problems with timeouts.
What you need is bi-directional communication based on fact that service exposes one way service and client exposes one way service as well (services can be two-way to support some kind of delivery notification). You will pass client's address in the first request as well as some correlation Id to differ multiple requests passed from the same client. You will call client service when the request is completed. Yes, you will have to manage all the stuff by yourselves.
If you are in intranet environment and your clients will be Windows based you can even think about changing your transport protocol to MSMQ because it has built-in support for all these requirements.
Edit:
I checked your updated question and you would call your communication pattern as Soap Messaging. I have never did it with WCF but it should be possible. You need to expose service on both sides of the communication - you can build your service to exactly follow needed contracts. When your service receives call you can use OperationContext.Current.IncommingMessageHeaders to access WS-Addressing information. You can store this information and use them later if you need them. The problem is that these information will not contain what you need. You have to fill them first on the client. This is generally possible by using OperationContextScope and filling OperationContext.Current.OutgoingMessageHeaders. What I'm affraid is that WCF can be "to clever" and override your changes to outgoing WS-Addressing information. I will probably try it myself during weekend.
It turns out the Windows Workflow Foundation (v4) does indeed facilitate this sort of message exchange.
Because WF allows you to decouple the request and response, and do basically whatever you want in the middle, including persist the workflow, idle it, and go outside and cut the grass, you get this capability "for free". Information can be found at these URLs:
Durable Duplex (MSDN)
Workflow 4 Services and duplex communications

Is there an nServiceBus sample for Pub/Sub with WCF?

It's a really common pattern and I'm finding it a nightmare to implement!
--
The WcfIntegration sample is almost what I'm looking for in that it receives messages via a WCF endpoint. However, it receives messages back on itself. I want a separate subscriber.
So what I'm trying to do is merge the WcfIntegration and pub/sub samples.
The real need is for a website to call a class library, which then calls the WCF endpoint of the publisher.
A subscriber then picks receives a message that the publisher publishes, and does whatever with it.
--
Rob
You shouldn't need the interface IEventMessageService; NSB handles that for you.
In my local example, I mapped the messages to myself. For you this would be:
<UnicastBusConfig><MessageEndpointMappings>
<add Messages="MyMessages" Endpoint="MyPublisherInputQueue"/>
</MessageEndpointMappings></UnicastBusConfig>
You also need to move your Publish to the actual handler. Right now, it is only happening once (at startup):
public void Handle(EventMessage message)
{
bus.Publish(message);
bus.Return((int)ErrorCodes.None);
}
Make sure your infrastructure is primed, i.e. the queue is transactional, and MSDTC is running.
I'm willing to bet that since there is no mapping, once the service is called, it doesn't know where to put the messages (it calls Bus.Send() internally). I didn't look at the subscribers since that didn't seem to be the issue.
I've finally got it to work here:-
http://code.google.com/p/nservicebus-wcf-pubsub/downloads/list
Anyone is welcome to improve the code.

WCF / MSMQ "time-to-be-received has elapsed" dead letter queue issue

I'm doing testing against some software I've written. The test enqueues messages into MSMQ via WCF at a rate faster than than my software can dequeue and process them. This shouldn't be a problem, since that is MSMQ's intended purpose, but if I enqueue enough messages to where it's taking my software more than 24 hours to process, those messages will get moved to the "Transactional dead-letter messages" queue and have their Class set to "The time-to-be-received has elapsed".
The only configurable that I can find is on the binding itself:
<bindings>
<netMsmqBinding>
<binding timeToLive="7.00:00:00" /> <!-- 7 days -->
...
I use this binding both when enqueuing and dequeuing and it doesn't seem to do the trick. Setting the value 2 seconds does have an effect, but setting it longer than 1 day, including to its max value (24 days) does not.
Is there another way to lengthen this time-to-be-received window? I can't find anything else to configure (when sending the message or creating the queue).
The timeToLive attribute on the binding itself is, in fact, the only configurable necessary. I went back through all my configurations and apparently missed a spot. From "Programming WCF Services":
The TimeToLive property is only
relevant to the posting client, and
has no affect on the service side, nor
can the service change it. TimeToLive
defaults to one day.
I've had the test running all weekend now, progressing 1,000,000 messages. Nothing has ended up in the dead-letter queue yet.
I'm not 100% sure, but I believe that the TimeToLive property only sets the Time-To-Reach-Queue msmq property, but I don't know of a built-in way right now of setting the Time-To-Be-Received property...

Cofiguring an endpoint to act both as worker and subscriber

Is it possible to configure an endpoint to act as a worker retrieving jobs from a distributor AND subscribe to some kind of messages?
I have the following scenario ( adapted to sale terminology)
*) a central department publishes every now and then a list of the new prices. All workers have to be notified. That means, a worker should subscribe to this event.
*) when a new order arrives at the central, it sends it to the distributor, which send it to the next idle worker to be processed. That means, a worker have to be configured to receive messages from the distributor.
I use the following configuration:
<MsmqTransportConfig
InputQueue="worker"
ErrorQueue="error"
NumberOfWorkerThreads="2"
MaxRetries="5"
/>
<UnicastBusConfig
DistributorControlAddress="distributorControlBus"
DistributorDataAddress="distributorDataBus" >
<MessageEndpointMappings>
<add Messages="Events" Endpoint="messagebus" />
</MessageEndpointMappings>
</UnicastBusConfig>
When I configure it only as a worker or only as a subscriber everything works as expected, but not when I configure it as both.
I discovered that a message arrives at the input queue of the central with the address of the distributor as return address instead of worker address, and the publisher recognize no subscriber in this case.
Any ideas? Thanks in advance.
Workers are not supposed to be used in that way IFAIK. I think the way to go would be to have your central subscribe to the prices and when a "NewOrderMessage" arrives enrich that data with the required prices (perhaps only prices for the products in that particular order) and send a new ProcessOrderRequest to the input queue of the distributor.
Another way would be to have the process that sends the order request to include the prices in the order request.
Does that make any sense?
/Andreas
Workers behind a distributor is how you scale out a single logical subscriber, not how you handle multiple logical subscribers. The point is that only a single worker out of the pool of workers should get a given message, in which case, you want all workers to look the same to the publisher - which is why the address of the distributor is given.
If you have multiple logical subscribers that you want to scale out, give each one of them their own distributor.