This post applies to both Dynamics CRM Online and On-Premise. The scenario is where you need to keep another system synchronized with changes to Dynamics CRM entities. To make this loosely coupled you can write messages to a queue. If your target system is unavailable, the queue can store messages until it comes back online. The same design pattern is recommended for Dynamics CRM Online where messages are written to Azure Service Bus queue. You then have a process on-premise (it my be an ESB) that reads messages from the queue and sends then on to the target system.
This post stems from work I did on a previous project where we used CRM on-premise to write messages to MSMQ. If you are reading this far I assume you already know about Ordered Delivery but here is the bottom line:
If you want to maintain Ordered Delivery you must use Synchronous Plugins.
If you use a plugin registered for asynchronous it may appear to give you Ordered Delivery 4 out of 5 times, but you cannot guarantee it for all messages.
You can spend the time proving it for yourself or read this explanation.
We had a custom entity for address that meant you could create an address that was the primary address or the regulatory address or both. The business rule was that you could only have one active address for primary and regulatory. To achieve this we created a plugin on that fires on Create of an address and as a Pre-Operation, if you set the both primary and regulatory flags on the address to true it checks if any existing addresses are primary or regulatory, sets them to false and then deactivates the address(es). Now the target system has to obey the same logic so we need to send any messages to it n the correct order, i.e. in ordered delivery.
So I created a plugin that was generic and would write a message out to MSMQ. I registered it to run as a Post Operation on Create and Update of an Address and set it to run Asynchronously.
In one test case we have two existing addresses one set as primary, the other set as regulatory (lets call them 'Primary' and 'Regulatory'), We create a new address ('New') and set it to both primary and regulatory. That creates 5 messages.
1. Update of Primary to set the primary flag to false
2. Update of Primary when status is set to deactivate
3. Update of Regulatory to set the regulatory flag to false
4. Update of Regulatory when status is set to deactivate
5. Create of the New address
Now you want to maintain the order that the addresses were written to the database. The Create must come last or you've broken the business rule about only have one active primary or regulatory address. With the on-premise CRM I could examine the Asynchronous table and could see the 5 messages there. They were flagged as belonging to the same transaction but when you looked at the processed time they were all identical. All five records are executed simultaneously and its a matter of chance which message gets in the queue first. There is an order, but its not consistent.
BizTalk works in a similar way to the CRM Asynchronous Service and its architected that way for performance reasons.
When I changed the plugin to work synchronously then it does maintain the correct order of the messages. You do need to pay attention though to the Rank when you have multiple plugins registered on the same entity for the same stage. By default, Rank is zero but you can put any integer up to 99 into it, and this will set the order that the plugins fire in. I wanted my message to be the last plugin to execute so I set it to 99. Remember though that it affects the order
of the plugins within the same stage. The plugin pipeline always executes as
1. Pre-Validation
2. Pre-Operation (before the database write)
3. Post-Operation(after the database write)
Here is the bottom line again
If you want to maintain Ordered Delivery you must use Synchronous Plugins.
Showing posts with label MSMQ. Show all posts
Showing posts with label MSMQ. Show all posts
Saturday, July 4, 2015
Sunday, July 18, 2010
Writing to MSMQ
I was recently trying to write a message to MSMQ on a remote server. I knew there were two steps but I didn't realize there was a third.
1. Modify the Queue name to the correct format
2. On the MSMQ queue give write access to the account you are running under
3. Install MSMQ on the source server
MSMQ name
The MSMQ format name is a particular structure you need to get right - including the case:
FormatName:DIRECT=OS:<servername>\private$\<queuename>
Write Access
If your code was running as a web service as mine was, then the App Pool identity must be a domain account and that account needs to have write access to the MSMQ on the target server.
Install MSMQ locally
I hadn't relaized this. You must install MSMQ in the local server where the code is running. The reason is that it logs messages in an Outbound Queue. This is what you would need if you were running in an off-line situation and then wanted the messages forwarded when you were on-line. I did not relaize that it would also do this even with a permanently connected enviroment. So install MSMQ locally and life will be good.
1. Modify the Queue name to the correct format
2. On the MSMQ queue give write access to the account you are running under
3. Install MSMQ on the source server
MSMQ name
The MSMQ format name is a particular structure you need to get right - including the case:
FormatName:DIRECT=OS:<servername>\private$\<queuename>
Write Access
If your code was running as a web service as mine was, then the App Pool identity must be a domain account and that account needs to have write access to the MSMQ on the target server.
Install MSMQ locally
I hadn't relaized this. You must install MSMQ in the local server where the code is running. The reason is that it logs messages in an Outbound Queue. This is what you would need if you were running in an off-line situation and then wanted the messages forwarded when you were on-line. I did not relaize that it would also do this even with a permanently connected enviroment. So install MSMQ locally and life will be good.
Subscribe to:
Posts (Atom)