You may meet intermittent error when running DotNetFile adapter in SDK on multiple host instances to access a remote file share.
You may meet intermittent error when running DotNetFile adapter in SDK on multiple host instances to access a remote file share.
The DotNetFile adapter in SDK has a different behavior to process 0 byte files than the built-in File adapter (0 byte files will be deleted directly by File adapter). Therefore, sometimes we will need to use this adapter for 0 byte file processing. However, you may meet intermittent error like below when running DotNetFile adapter in SDK on multiple host instances to access a remote file share.
This is because the file hander is owned by other process immediately when an adapter instance is trying to delete or rename the file. To fix the error, we have to add some 'Retry logic' in the adapter code when deleting or renaming files and add Guid to temp file names.
Below are the modified code snippets:
privatevoid PickupFilesAndSubmit ()
{
//Trace.WriteLine("[DotNetFileReceiverEndpoint] PickupFilesAndSubmit called");
int maxBatchSize = this.properties.MaximumBatchSize;
int maxNumberOfFiles = this.properties.MaximumNumberOfFiles;
List<BatchMessage> files = newList<BatchMessage>();
long bytesInBatch = 0;
DirectoryInfo di = newDirectoryInfo(this.properties.Directory);
FileInfo[] items = di.GetFiles(this.properties.FileMask);
//Trace.WriteLine(string.Format("[DotNetFileReceiverEndpoint] Found {0} files.", items.Length));
foreach (FileInfo item in items)
{
// only consider files that are not read only
if (FileAttributes.ReadOnly == (FileAttributes.ReadOnly & item.Attributes))
continue;
// only download files that are less than the configured max file size
if (false == CheckMaxFileSize(item))
continue;
string fileName = Path.Combine(properties.Directory, item.Name);
//if (fileName.Contains("BTS-WIP"))
// System.Diagnostics.EventLog.WriteEntry("CCMS Adapter", "File Name: " + fileName);
string renamedFileName;
if ( this.properties.WorkInProgress.Length > 0 )
renamedFileName = fileName +
this.properties.WorkInProgress + System.Guid.NewGuid().ToString();
else
renamedFileName =
null;
// If we couldn't lock the file, just move onto the next file
IBaseMessage msg = CreateMessage(fileName, renamedFileName);
if ( null == msg )
continue;
if ( null == renamedFileName )
files.Add(
newBatchMessage(msg, fileName, BatchOperationType.Submit));
else
files.Add(
newBatchMessage(msg, renamedFileName, BatchOperationType.Submit));
// keep a running total for the current batch
bytesInBatch += item.Length;
// zero for the value means infinite
bool fileCountExceeded = ((0 != maxNumberOfFiles) && (files.Count >= maxNumberOfFiles));
bool byteCountExceeded = ((0 != maxBatchSize) && (bytesInBatch > maxBatchSize));
if (fileCountExceeded || byteCountExceeded)
{
// check if we have been asked to stop - if so don't start another batch
if (this.controlledTermination.TerminateCalled)
return;
// execute the batch
SubmitFiles(files);
// reset the running totals
bytesInBatch = 0;
files.Clear();
}
}
privateIBaseMessage CreateMessage (string srcFilePath, string renamedFileName)
{
Stream fs;
bool renamed = false;
// Open the file
try
{
if (!String.IsNullOrEmpty(renamedFileName))
{
//Trace.WriteLine("[DotNetFileReceiverEndpoint] Renaming file " + srcFilePath);
File.Move(srcFilePath, renamedFileName);
//Trace.WriteLine("[DotNetFileReceiverEndpoint] Renaming file Done " + renamedFileName);
renamed =
true;
//Trace.WriteLine("[DotNetFileReceiverEndpoint] Opening file " + renamedFileName);
fs =
File.Open(renamedFileName, FileMode.Open, FileAccess.Read, FileShare.None);
//Trace.WriteLine("[DotNetFileReceiverEndpoint] Opening file Done " + renamedFileName);
}
else
{
fs =
File.Open(srcFilePath, FileMode.Open, FileAccess.Read, FileShare.None);
}
}
catch(Exception)
{
// If we renamed the file, rename it back
//Trace.WriteLine("[DotNetFileReceiverEndpoint] Error occured. Renamed: " + renamed + " Renamed File Name: " + renamedFileName);
if (renamed)
{
// Trace.WriteLine("[DotNetFileReceiverEndpoint] On error renaming file back " + renamedFileName);
bool bRenameBack = false;
int bRetryCount = 0;
while (!bRenameBack && bRetryCount < 1000)
{
try
{
File.Move(renamedFileName, srcFilePath);
// Trace.WriteLine("[DotNetFileReceiverEndpoint] On error renaming file back Done " + renamedFileName);
}
catch (Exception)
{
// Trace.WriteLine("[DotNetFileReceiverEndpoint] On error renaming file back Failed " + renamedFileName);
System.Threading.
Thread.Sleep(10);
bRetryCount++;
}
}
}
returnnull;
}
internalvoid OnBatchComplete(bool overallStatus)
{
//Trace.WriteLine(string.Format("[DotNetFileReceiverEndpoint] OnBatchComplete called. overallStatus == {0}.", overallStatus));
if (overallStatus == true) //Batch completed
{
//Delete the files
foreach (BatchMessage batchMessage in messages)
{
//Close the stream so we can delete this file
batchMessage.Message.BodyPart.Data.Close();
bool bDeleted = false;
int bRetryCount = 0;
while (!bDeleted && bRetryCount < 1000000 )
{
try
{
File.Delete((string)batchMessage.UserData);
bDeleted =
true;
}
catch (Exception ex)
{
//Trace.WriteLine("[DotNetFileReceiverEndpoint] {0}", ex.Message);
System.Threading.
Thread.Sleep(10);
bRetryCount++;
}
}
}
}
}
Best regards,
WenJun Zhang