Occasionally, you may see errors/warnings in the event log when you disable a WCF-Custom receive location which was configured to use the polling feature of the oracle adapter, especially if the polling interval is set to a low value. You would see these errors almost every time you disabled the location, if Polling Interval = 0.One of the errors would be:
"The adapter "WCF-Custom" raised an error message. Details "System.InvalidOperationException: The reply is invalid because the underlying transaction object has been disposed. This occurs if the polling interval expires before receiving a reply. Use a higher value for polling interval."
Another would be:
"The adapter "WCF-Custom" raised an error message. Details "System.Transactions.TransactionAbortedException: The transaction has aborted."
In some cases you may see another error as well: "Connection must be open for this operation".
What's going on?
To understand what's going on, let’s take a closer look at how polling happens in the Oracle Adapter. I'll avoid the gory code level details and present a relatively high level picture.
Simply speaking, at any instant during a running polling scenario, the Adapter may be considered to be in either of the following two states (Figure 1):
- Actively Polling:
The adapter is polling for a message, or waiting for the message to be consumed. In fact this state may itself be considered to be made up of the following sub-states (the above state transition diagram may be redrawn to accomodate this detail):-
Poll Msg -> Msg Available -> Msg consumed -> Polling Transaction Committed (or aborted) -> (Go to 'Poll Msg' or 'Sleeping' depending on the remaining polling interval)
The reason for combining these steps into a single state is that they are executed as part of a single transaction.
If the Polling Interval specified is greater than the time required to complete all the tasks mentioned above in the 'Actively Polling' state, the adapter switches to the 'Sleeping' state for the remaining period of the Polling Interval, after which it transitions back to the 'Actively Polling' state ('Poll Msg' to be specific) and polls for the next message.
Clearly, if the polling interval is small (compared to the time required to complete the tasks in 'Actively Polling' state), at any random point of time the adapter is more likely to be in the 'Actively Polling' state than in the 'Sleeping' state.
Note that Polling Interval = 0 is a special case which tells the adapter to take as much time as it needs to complete the set of steps in the 'Actively Polling' state and poll for the next message as soon as previous transaction has been completed. Thus, in this case, the adapter never goes to the 'Sleeping' state.
Also note that when Polling Interval > 0, there’s no guarantee that the adapter will be able to complete all the above steps within the specified interval. If it is unable to do so, the polling transaction will be aborted and the adapter will go back to poll the next message (if Retry Count > 0). In this case too, the adapter will never go to the ‘Sleeping’ state.
Now if the 'Receive Location' is disabled when the adapter is in 'Sleeping' state, everything would be fine. However, if the adapter happened to be in the 'Actively Polling' state at that point, it may lead to problems. In most cases the following sequence of events will take place at the instant when you disable the receive location:-
- The Receive Location (WCF-Custom adapter) is consuming an available message (it sends an acknowledgement/reply to the Oracle Adapter to indicate whether or not it has successfully consumed the message)
- The WCF-custom adapter aborts its own transaction and you see a 'Transaction Aborted' exception.
- The Oracle adapter receives the instruction to stop polling and aborts the current transaction.
- If the message had a part which was being streamed by the adapter (e.g. a blob column), you might see an exception saying "Connection must be open for this operation".
- By the time the last reply from the WCF-Custom adapter reaches the Oracle adapter, the corresponding transaction has already been aborted and the transaction object disposed. This is when you see the exception saying "System.InvalidOperationException: The reply is invalid because the underlying transaction object has been disposed. This occurs if the polling interval expires before receiving a reply. Use a higher value for polling interval."
The above picture is rather simplified (the thread level details are missing) and may not be completely accurate but I hope it gives some insight into why you see those errors while disabling the receive location and how they are related to the Polling Interval.
Ok, but what are the implications? What do I do if I see this error?
You don’t need to do anything. As explained above, the error is a result of how polling happens and is benign. The only thing you need to keep in mind when you see this error is that the last transaction which the adapter was executing has been aborted. (So, effectively, the last post-poll statement was not executed).