Tuesday, December 3, 2013

Custom File Adapter for Pooling Interval

The Pooling Interval property decide how long system should wait to poll the receive location again, if it get no message last time it polls.

Polling intervals in File/FTP adapters not works as expected, This is how it works
1. You drop 4 files at a time.
2. Biztalk File/FTP adapter reads 1 file at a time (according to batch size=1)
until the receive location is empty.
          This means while your first file being picked up, Biztalk FTP/File adapter identifies 3 more files are pending. So FTP/File adapter discards the polling interval and pick one after the other until your receive location is empty.

3.If the receive location is empty , it waits util the next polling interval.

I think the batching works well but it seem like it does not wait for the polling interval.

We want to change the behavior for the Pooling Interval property, it is all about performance. We don't want our CPU to be fully occupied with receiving messages because lots of them arrived is a short period of time, maybe making our system to work really slow, expiring timeout of other ports.

Microsoft released all the most important BizTalk parts with source code, we can locate those in C:\Program Files (x86)\Microsoft BizTalk Server 2010\SDK\Samples and in this directory exist the source code of the BizTalk file adapter, HTTP adapter, and we can find all the base class library here which will be useful to develop a new BizTalk Adapter.

we'll use the source code of the File Adapter (located in AdaptersDevelopment\File Adapter)



In the directory we'll find ,BizTalk Project directory with one BTS sample, Design Time directory is a project to manage adapter configuration, Runtime directory is the project of adapter runtime.

     Runtime project is the most important, open it, in this project you can observe the two principal files DotNetFileReceiverEndpoint.cs that contain the code for receive the stream and DotNetFileTransmitterEndpoint.cs that contain the code to transmit the stream.
In DotNetFileReceiverEndpoint.cs

  • public void ControlledEndpointTask (object val)


        {
            if (this.controlledTermination.Enter())
            {
                try
                {
                    lock (this)
                    {
                        this.EndpointTask();                      
                    }
                    GC.Collect();                  
                }
                finally
                {
                    this.controlledTermination.Leave();
                    Thread.Sleep(new TimeSpan(0, 0, 0, ((int)this.properties.PollingInterval)));
                }
            }
        }

  •     In PickupFilesAndSubmit(), modify the existing code with the below one.

         FileInfo[] items = di.GetFiles(this.properties.FileMask)
               Add System.Linq; namespace at the using block.
        FileInfo[] items = di.GetFiles(this.properties.FileMask).Take(maxNumberOfFiles).ToArray();
     


  • please add the below code, to avoid The process cannot access the file because it is being used by another process error. 

               // If we couldn't lock the file, just move onto the next file
                IBaseMessage msg = CreateMessage(fileName, renamedFileName);
                             
                MemoryStream ms = new MemoryStream();
                msg.BodyPart.Data.CopyTo(ms);
                msg.BodyPart.Data.Position = 0;

                if ( null == msg )
                    continue;

                if ( null == renamedFileName )
                    files.Add(new BatchMessage(msg, fileName, BatchOperationType.Submit));
                else
                    files.Add(new BatchMessage(msg, renamedFileName, BatchOperationType.Submit));
             
                if (ms.CanSeek)
                {
                    ms.Position = 0;
                }
                msg.BodyPart.Data = ms;

                //  keep a running total for the current batch
                bytesInBatch += item.Length;

Now we can rebuild our adapter and have to register it.

To register the adapter we must execute the registry file StaticAdapterManagement.reg, we found some possible issues in this file.

The first is the directories, check all path directory because all are wrong:

  • C:\Program Files\Microsoft BizTalk Server 2010\SDK\Samples\AdaptersDevelopment\FileAdapter\Runtime\bin\Debug\Microsoft.BizTalk.SDKSamples.Adapters.DotNetFile.Runtime.dll”


  • “OutboundEngineCLSID”=”{024DB758-AAF9


  • Is not FileAdapter but File Adapter
The second, check if your sample is under Program Files or Program Files (x86) in case modify the path or create your own different directory project.

The third and the most important is, if your BizTalk run in 64 bit mode you must modify the registry keys because BizTalk server in 64 bit search configuration under Wow6432Node



So, for example, if you want work with BizTalk configuration in 32 bit mode the correct string is
[HKEY_CLASSES_ROOTCLSID{62018D08-281A-415b-A6D3-6172E3762867}]
in 64 bit is
[HKEY_CLASSES_ROOTWow6432NodeCLSID{62018D08-281A-415b-A6D3-6172E3762867}]

In the BizTalk Admin console, right click on the adapters, new and select Static DotNetFile, for the adapter name as you want.



Restart the host instance
Create one receive port, one send with correct filter and test the solution





The result must be this

Here we have set the Number of files in Batch as 2 and Pooling interval as 60 seconds.

3 comments:

  1. This is good code. Very well explained and easy to understand. I would only add the reason why the Polling Interval property does not work. It is because its designed to be used only with non windows file locations. If the file location is a windows based file location BizTalk will listen to the notifications services when a file is dropped, and will pick it up, regardless of the Polling Interval, because it is not really polling. I think the best way to look at it is, if the file location is windows based and Notification Services is available, the FILE adapter will not poll, but will listen to the notification services. When NS is not available, it polls, based on the Polling Interval specified.

    ReplyDelete
  2. Ravi, did you have a chance to test this with a file location that has the source folder on a non windows or out of domain machine? This might cause it to double the polling interval in those cases. I haven't tested it, but it is a strong possibility.

    ReplyDelete
    Replies
    1. I have tested this in Windows. it'll not exactly double the pooling interval.

      i.e in the ControlledEndpointTask(), we have Applied called thread.sleep with the pooling interval value. So the pooling interval would be number of seconds elapsed + pooling interval

      Delete