public async Task <bool> BatchRun(BatchJob opts, CancellationToken cancellationToken = default) { m_UserLogger.WriteLine($"Batch macro running started"); var batchStartTime = DateTime.Now; var allFiles = PrepareJobScope(opts.Input, opts.Filters, opts.Macros).ToArray(); m_UserLogger.WriteLine($"Running batch processing for {allFiles.Length} file(s)"); m_ProgressHandler.SetJobScope(allFiles, batchStartTime); if (!allFiles.Any()) { throw new UserMessageException("Empty job. No files matching specified filter"); } TimeSpan timeout = default; if (opts.Timeout > 0) { timeout = TimeSpan.FromSeconds(opts.Timeout); } IXApplication app = null; Process appPrc = null; if (cancellationToken != default) { cancellationToken.Register(() => { m_UserLogger.WriteLine($"Cancelled by the user"); TryShutDownApplication(appPrc); }); } var jobResult = false; try { await Task.Run(() => { var curBatchSize = 0; for (int i = 0; i < allFiles.Length; i++) { var curAppPrc = appPrc?.Id; var curFile = allFiles[i]; var res = AttemptProcessFile(ref app, ref appPrc, curFile, opts, cancellationToken); m_ProgressHandler?.ReportProgress(curFile, res); if (!res && !opts.ContinueOnError) { throw new UserMessageException("Cancelling the job. Set 'Continue On Error' option to continue job if file failed"); } if (appPrc?.Id != curAppPrc) { curBatchSize = 1; } else { curBatchSize++; } if (opts.BatchSize > 0 && curBatchSize >= opts.BatchSize && !cancellationToken.IsCancellationRequested) { m_UserLogger.WriteLine("Closing application as batch size reached the limit"); TryShutDownApplication(appPrc); curBatchSize = 0; } } }).ConfigureAwait(false); jobResult = true; } finally { TryShutDownApplication(appPrc); } var duration = DateTime.Now.Subtract(batchStartTime); m_ProgressHandler.ReportCompleted(duration); m_UserLogger.WriteLine($"Batch running completed in {duration.ToString(@"hh\:mm\:ss")}"); return(jobResult); }
private bool AttemptProcessFile(ref IXApplication app, ref Process appPrc, JobItemFile file, BatchJob opts, CancellationToken cancellationToken = default) { file.Status = JobItemStatus_e.InProgress; int curAttempt = 1; var macrosStack = new List <JobItemMacro>(file.Macros); TimeSpan?timeout = null; if (opts.Timeout > 0) { timeout = TimeSpan.FromSeconds(opts.Timeout); } while (curAttempt <= MAX_ATTEMPTS) { if (app == null || !IsAppAlive(app, appPrc) && !cancellationToken.IsCancellationRequested) { TryShutDownApplication(appPrc); var vers = m_AppProvider.ParseVersion(opts.VersionId); app = AttemptStartApplication(vers, opts.StartupOptions, cancellationToken, timeout); appPrc = app.Process; } IXDocument doc = null; CancellationTokenSource cancellationTokenSrc = null; CancellationToken timeoutCancellationToken = default; try { if (timeout.HasValue) { cancellationTokenSrc = new CancellationTokenSource(timeout.Value); timeoutCancellationToken = cancellationTokenSrc.Token; var thisAppPrc = appPrc; timeoutCancellationToken.Register(() => { TryShutDownApplication(thisAppPrc); }); } if (cancellationToken.IsCancellationRequested) { throw new JobCancelledException(); } var fileProcessStartTime = DateTime.Now; m_UserLogger.WriteLine($"Started processing file {file.FilePath}"); doc = app.Documents.FirstOrDefault(d => string.Equals(d.Path, file.FilePath)); var forbidSaving = false; if (doc == null) { doc = app.Documents.PreCreate <IXDocument>(); doc.Path = file.FilePath; var state = DocumentState_e.Default; if (opts.OpenFileOptions.HasFlag(OpenFileOptions_e.Silent)) { state |= DocumentState_e.Silent; } if (opts.OpenFileOptions.HasFlag(OpenFileOptions_e.ReadOnly)) { state |= DocumentState_e.ReadOnly; } if (opts.OpenFileOptions.HasFlag(OpenFileOptions_e.Rapid)) { state |= DocumentState_e.Rapid; } if (opts.OpenFileOptions.HasFlag(OpenFileOptions_e.Invisible)) { state |= DocumentState_e.Hidden; } if (opts.OpenFileOptions.HasFlag(OpenFileOptions_e.ForbidUpgrade)) { if (app.Version.Compare(doc.Version) == VersionEquality_e.Newer) { forbidSaving = true; if (!state.HasFlag(DocumentState_e.ReadOnly)) { m_UserLogger.WriteLine($"Setting the readonly flag to {file.FilePath} to prevent upgrade of the file"); state |= DocumentState_e.ReadOnly; } } } doc.State = state; doc.Commit(cancellationToken); } if (!opts.OpenFileOptions.HasFlag(OpenFileOptions_e.Invisible)) { app.Documents.Active = doc; } AttempRunMacros(app, doc, macrosStack, opts.Actions, forbidSaving, cancellationToken); if (file.Macros.All(m => m.Status == JobItemStatus_e.Succeeded)) { file.Status = JobItemStatus_e.Succeeded; } else { file.Status = file.Macros.Any(m => m.Status == JobItemStatus_e.Succeeded) ? JobItemStatus_e.Warning : JobItemStatus_e.Failed; } m_UserLogger.WriteLine($"Processing file '{file.FilePath}' completed. Execution time {DateTime.Now.Subtract(fileProcessStartTime).ToString(@"hh\:mm\:ss")}"); return(file.Status != JobItemStatus_e.Failed); } catch (Exception ex) { var errDesc = ""; if (cancellationToken.IsCancellationRequested) { throw new JobCancelledException(); } if (timeoutCancellationToken.IsCancellationRequested) { errDesc = "Timeout processing document"; } else { if (ex is OpenDocumentFailedException) { errDesc = $"Failed to open document {file.FilePath}: {(ex as OpenDocumentFailedException).Message}"; } else { errDesc = "Failed to process document"; } } m_UserLogger.WriteLine($"{errDesc}. Attempt: {curAttempt}"); curAttempt++; } finally { cancellationTokenSrc?.Dispose(); TryCloseDocument(doc); } } file.Status = JobItemStatus_e.Failed; m_UserLogger.WriteLine($"Processing file '{file.FilePath}' failed"); return(false); }