MORE INFORMATION
In BizTalk Server 2000, you can programmatically integrate applications through the BizTalk Configuration Object Model, thereby extending and customizing the functionality of the server to suit a specific business and information-exchange need. The interface reference provides all the information necessary for programmers of the Microsoft Visual Basic 6.0 and Microsoft Visual C++ programming languages to use or extend BizTalk Server 2000.
A custom AIC is implemented as COM objects that the BizTalk Server state engine calls to deliver data to an application. If a messaging port is configured in BizTalk Server 2000 to include the use of an AIC for application integration, this component is automatically instantiated and passed the requisite data. The custom component then determines how to handle communicating this data back to the application. This can be done by using private API calls, invoking other COM objects, using database writes, and so on.
When you develop an AIC using Visual Basic 6.0, the component may experience performance issues when it is running in a BizTalk environment. Visual Basic 6.0 supports two types of ActiveX DLL component threading: single-threaded (no registry setting) or marked as "Apartment," which is the default for Visual Basic. The BizTalk activator thread runs in the multi-threaded apartment (MTA). As a result, activation of a component marked as "Apartment" will occur in the "host STA," and not in the MTA. COM creates the single (one per process) host STA as the home for all components marked as "Apartment" that are instantiated by an activator thread living in the MTA. If that MTA activator thread instantiates one hundred instances of "Apartment" components, all instances will live in the single host STA, which effectively causes all method calls into these instances to be serialized. In addition, calls from the activator thread to the host STA are marshaled through LRPC, which adds an additional hit on performance.
To resolve this problem, do not use the "Apartment" threading model. Visual Basic 6.0 does not currently offer any other threading options, but Visual C++ allows the creation of COM components marked as "Free." When you are building an AIC and performance is a primary consideration, the AIC should be written in Visual C++ and marked as "Free."
When an MTA activator thread instantiates a component marked as "Free", it's methods can be called by any thread in the MTA. This differs from an "Apartment" component, which is restricted to receiving all method calls from only its activator thread. The net effect of an MTA thread instantiating "Free" component (as opposed to an "Apartment" component) is a double gain in performance. COM does not need to set up the overhead of marshaling (calls are direct) as it does with mixed threading models between a component and its activator. In addition, a component marked as "Free" can be called by any thread at any time. This is ideal in a server's multithreaded hosting environment, and it provides the maximum performance because all of the allocated BizTalk Messaging engine worker threads are accessing the AIC simultaneously. This improves the overall throughput of the AIC and makes the AIC more scalable.
The BizTalk Messaging engine allocates four worker threads per processor (default) for processing documents or work items internally. As part of this processing, the BizTalk Server state engine uses the Microsoft Distributed Transaction Coordinator (MSDTC). The BizTalk Server state engine allows a total time of 60 minutes for the MSDTC transaction or the processing of a document through the BizTalk Server state engine. (This total includes any processing time spent in a custom AIC.) If the transaction exceeds the allotted time, the transaction is aborted. The MSDTC will then generate event log errors that are similar to the following:
Error 1:
The database call failed and returned the following error string: "Distributed transaction completed. Either enlist this session in a new transaction or the NULL transaction.". If possible, we will attempt to retry this call.
The following stored procedure call failed:
"{ call dta_log_outbound_details( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)}".
Error 2:
The following stored procedure call failed:
"{ call dta_log_outbound_details( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)}".
Unspecified error
Changes could not be committed to the database.
Error 3:
The database call failed and returned the following error string:
"Distributed transaction completed. Either enlist this session in a new transaction or the NULL transaction.". If possible, we will attempt to retry this call. The following stored procedure call failed:
"{ call cs_create_SuspendedQ_from_WorkQ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)}".
Error 4:
The following stored procedure call failed:
"{ call cs_create_SuspendedQ_from_WorkQ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)}".
Unspecified error
A new work item in the Suspended queue cannot be created.
This problem is more likely to occur on a multiprocessor system than on a single processors system. On a multiprocessor system, it is possible to queue transacted method calls across the many more worker threads that are allocated for a multiprocessor system, than it is (by default) on a single processor system.
Documents that are queued to be serviced by the Messaging engine are picked up by a single worker thread. This worker thread calls into the Visual Basic object and waits for the object to finish processing. When the worker thread has to wait to access a Visual Basic object, this adds to the total time of the processing of any single document, which can cause the MSDTC to abort the transaction and cause errors. For example, a worker thread running on a single processor system that implements a Visual Basic 6.0 component that takes 5 minutes to complete its work and return to BizTalk may take around 20 minutes total time to finish processing (4 worker threads x 5 minutes = 20 minutes). This is because its total processing time will include the time it has to wait for access to the Visual Basic object. When you consider the same component running on a multiprocessor system with 4 processors, a worker thread will exceed the maximum 1-hour MSDTC timeout set by BizTalk Server. This is because the longest outstanding request is greater than the MSDTC timeout (16 worker threads x 5 minutes = 80 minutes).
If you suspect that this may be happening, you can try and replace the AIC with one of the transports that is include with BizTalk Server. If this resolves the problem, you can safely assume that the Visual Basic 6.0 component has encountered the problem discussed in this article.
If you are considering using Visual Basic 6.0 to implement the AIC, the AIC COM component should run as a COM+ Server application. This will allow COM+ to manage the component threading model and other aspects of object activation. For more information on how to do this, see the following Web page: