Hi all,
We are using latest nuget available MIPS packages, 23.2.1.
we are experiencing troubles using NetFramework 4.7.2 TPE Parallel.For to perform parallel export;
the problem is not costant, but it actually appears from time to time, indicating in the event viewer
andThe Parallel.For code is
ConcurrentBag<string> resultCollection = new ConcurrentBag<string>();
int CYCLE = 3;
int min = 0;
int max = min + CYCLE;
if (max > sequences.Count)
{
max = sequences.Count;
}
int loop = 0;
while (min < sequences.Count)
{
loop++;
_log.Debug($"{(e.IsRecovery ? "Recovering Export" : "Exporting")}: Parallel loop # {loop}...");
_log.Debug($"Parallel loop: Max CYCLE # {CYCLE} - Min loop elem: {min } - Max loop elem: {max}...");
Parallel.For(min, max,
index =>
{
List<string> list = DoExportWork(new ExportWorkArg()
{
Connection = e.Connection,
FindCamera = findcamera,
Folder = folder,
IsRecovery = e.IsRecovery,
CameraTimeFrame = e.CameraTimeFrame,
SequenceNro = index + 1,
SequencesCount = sequences.Count,
LoopNo = loop,
Slot = sequences[index],
LogStart = e.LogStart,
LogEnd = e.LogEnd,
});
foreach (string s in list)
{
resultCollection.Add(s);
}
});
allFiles.AddRange(resultCollection);
min = max + 1;
max = min + CYCLE;
if (max > sequences.Count)
{
max = sequences.Count;
}
}
And the actual exporting Parallel.For calls is perfomed like
private List<string> DoExportWork(ExportWorkArg e)
{
List<string> result = new List<string>();
string sequenceFileName = Utilities.BuildFileName(e.FindCamera, e.Slot.From, e.Slot.To, Utilities.file_datetimeformat);
DateTime recTime = DateTime.Now;
//genera inizio e fine da inserire nel nome file e per fare l'acquisizione
DateTime slotStart = e.Slot.From;
DateTime slotEnd = e.Slot.To.AddMilliseconds(-1);
_log.Debug($"{(e.IsRecovery ? "Recovering Export" : "Exporting")}{(e.LoopNo != 0 ? $" Loop: {e.LoopNo} - " : "")} sequence # {e.SequenceNro} / {e.SequencesCount} : {e.LogStart.ToString(Utilities.log_datetimeformat)}-{e.LogEnd.ToString(Utilities.log_datetimeformat)} >> seq: {e.Slot.From.ToString(Utilities.log_datetimeformat)}-{e.Slot.To.ToString(Utilities.log_datetimeformat)}");
TimeSpan tsExport = e.Slot.To - e.Slot.From;
if (e.CameraTimeFrame < tsExport.TotalMinutes)
{
_log.Error($"{(e.IsRecovery ? "Recovering Export" : "Exporting")} camera [{e.FindCamera.FQID.ObjectId}]{(e.LoopNo != 0 ? $" Loop: {e.LoopNo} - " : "")} sequence # {e.SequenceNro} / {e.SequencesCount} : {e.LogStart.ToString(Utilities.log_datetimeformat)}-{e.LogEnd.ToString(Utilities.log_datetimeformat)} >> seq: {e.Slot.From.ToString(Utilities.log_datetimeformat)}-{e.Slot.To.ToString(Utilities.log_datetimeformat)} - ***WARNING*** tsExport: {tsExport.TotalMinutes} - cameraTimeFrame: {e.CameraTimeFrame}!");
}
{
try
{
e.Connection.Export(e.FindCamera,
slotStart,
slotEnd,
e.Folder,
$"{sequenceFileName}.mkv");
}
catch (Exception ex)
{
throw ex;
}
}
TimeSpan tsRecTime = DateTime.Now - recTime;
_log.Debug($"{(e.IsRecovery ? "Recovering Export" : "Exporting")}: File exported successfully! ({tsRecTime.TotalMilliseconds.ToString("N0")} msec.){(e.LoopNo != 0 ? $" - Loop: {e.LoopNo} " : "")}- sequence # {e.SequenceNro} / {e.SequencesCount} : {e.LogStart.ToString(Utilities.log_datetimeformat)}-{e.LogEnd.ToString(Utilities.log_datetimeformat)} >> seq: {e.Slot.From.ToString(Utilities.log_datetimeformat)}-{e.Slot.To.ToString(Utilities.log_datetimeformat)}");
string sequenceJsonFileName = $"{sequenceFileName}.json";
var slotSequences = new List<MilestoneExporterSequence>();
slotSequences.Add(e.Slot);
var jsonData = new
{
Sha256CRC = MilestoneExporter.Controller.Utilities.SHA256CheckSum(System.IO.Path.Combine(e.Folder, $"{sequenceFileName}.mkv")),
Sequences = slotSequences,
};
string jsonText = JsonConvert.SerializeObject(jsonData, formatting: Formatting.Indented);
string jsonFile = $@"{e.Folder}\{sequenceFileName}.json";
_log.Debug($"{(e.IsRecovery ? "Recovering Export" : "Exporting")}: Creating file {jsonFile} {(e.LoopNo != 0 ? $" - Loop: {e.LoopNo} " : "")}- sequence # {e.SequenceNro} / {e.SequencesCount}...");
File.WriteAllText(jsonFile, jsonText);
_log.Debug($"{(e.IsRecovery ? "Recovering Export" : "Exporting")}: File created successfully {(e.LoopNo != 0 ? $" - Loop: {e.LoopNo} " : "")}- sequence # {e.SequenceNro} / {e.SequencesCount}!");
result.Add($"{System.IO.Path.Combine(e.Folder, sequenceFileName + ".mkv")}");
result.Add($"{System.IO.Path.Combine(e.Folder, sequenceFileName + ".json")}");
return result;
}
which, finally, calls the export routine,
public void Export(Item camera, DateTime from, DateTime to, string folder, string filename)
{
_exporter = new VideoOS.Platform.Data.MKVExporter() { Filename = filename };
_exporter.Init();
_exporter.Path = folder;
var temp = new VideoOS.Platform.Item();
_exporter.CameraList = new List<VideoOS.Platform.Item>() { camera };
//_exporter.AudioList = camera.GetRelated().Where(x => x.FQID.Kind == Kind.Microphone || x.FQID.Kind == Kind.Speaker).ToList();
_exporter.AudioList = camera.GetRelated().Where(x => x.FQID.Kind == Kind.Microphone).ToList();
try
{
_exporter.StartExport(from, to);
_exporter.EndExport();
}
catch (Exception ex)
{
throw ex;
}
}
As you can see, the whole code is performed in Try/Catch blocks, and the initial Parallel.For is inserted in an additional Try/Catch block running in a loop of selected Camera items, but the code “just breaks” with the indications in the event viewer and the ErrorHandlers are not called…
Btw, we added even initial “uncatched exceptions” handlers,
public partial class MilestoneExporterService : ServiceBase
{
private Logger log;
private string servicepath = AppDomain.CurrentDomain.BaseDirectory;
private MilestoneExportServiceLibrary svc;
public MilestoneExporterService()
{
InitializeComponent();
this.CanHandlePowerEvent = true;
System.Windows.Forms.Application.ThreadException += new ThreadExceptionEventHandler(ApplicationThreadException);
AppDomain.CurrentDomain.UnhandledException += DomainUnhandledException;
}
private void DomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
if (log != null)
{
log.Error($"FATAL DomainUnhandledException - {((Exception)e.ExceptionObject).Message}");
log.Error($"StackTrace: {((Exception)e.ExceptionObject).StackTrace}");
}
}
private void ApplicationThreadException(object sender, ThreadExceptionEventArgs t)
{
if (log != null)
{
log.Error($"FATAL ApplicationThreadException - {t.Exception.Message}");
}
}
protected override void OnStart(string[] args)
{
....
But those 2 handlers are not called at all, and our service just “shuts down”….
Thanking you in advance for your kind support, and please excuse my poor English…
--
Andrea


