/// <summary> /// /// </summary> /// <param name="reason"></param> /// <param name="key"></param> /// <exception cref="InvalidStudyStateOperationException">Study is in a state that reprocessing is not allowed</exception> public void ReprocessStudy(String reason, ServerEntityKey key) { StudyStorageAdaptor adaptor = new StudyStorageAdaptor(); StudyStorage storage = adaptor.Get(key); StudyStorageLocation storageLocation = StudyStorageLocation.FindStorageLocations(storage)[0]; StudyReprocessor reprocessor = new StudyReprocessor(); reprocessor.ReprocessStudy(reason, storageLocation, Platform.Time); }
/// <summary> /// Do the actual rebuild. On error, will attempt to reprocess the study. /// </summary> public void RebuildXml() { string rootStudyPath = _location.GetStudyPath(); try { using (ServerCommandProcessor processor = new ServerCommandProcessor("Rebuild XML")) { var command = new RebuildStudyXmlCommand(_location.StudyInstanceUid, rootStudyPath); processor.AddCommand(command); var updateCommand = new UpdateStudySizeInDBCommand(_location, command); processor.AddCommand(updateCommand); if (!processor.Execute()) { throw new ApplicationException(processor.FailureReason, processor.FailureException); } Study theStudy = _location.Study; if (theStudy.NumberOfStudyRelatedInstances != command.StudyXml.NumberOfStudyRelatedInstances) { // We rebuilt, but the counts don't match. throw new StudyIntegrityValidationFailure(ValidationErrors.InconsistentObjectCount, new ValidationStudyInfo(theStudy, _location.ServerPartition), string.Format( "Database study count {0} does not match study xml {1}", theStudy.NumberOfStudyRelatedInstances, command.StudyXml.NumberOfStudyRelatedInstances)); } Platform.Log(LogLevel.Info, "Completed reprocessing Study XML file for study {0}", _location.StudyInstanceUid); } } catch (Exception e) { Platform.Log(LogLevel.Error, e, "Unexpected error when rebuilding study XML for directory: {0}", _location.FilesystemPath); StudyReprocessor reprocessor = new StudyReprocessor(); try { WorkQueue reprocessEntry = reprocessor.ReprocessStudy("Rebuild StudyXml", _location, Platform.Time); if (reprocessEntry != null) { Platform.Log(LogLevel.Error, "Failure attempting to reprocess study: {0}", _location.StudyInstanceUid); } else Platform.Log(LogLevel.Error, "Inserted reprocess request for study: {0}", _location.StudyInstanceUid); } catch(InvalidStudyStateOperationException ex) { Platform.Log(LogLevel.Error, "Failure attempting to reprocess study {0}: {1}", _location.StudyInstanceUid, ex.Message); } } }
/// <summary> /// /// </summary> /// <param name="item"></param> /// <param name="reason"></param> /// <returns></returns> /// <exception cref="InvalidStudyStateOperationException">Study is in a state that reprocessing is not allowed</exception> protected static AutoRecoveryResult PerformAutoRecovery(Model.WorkQueue item, string reason) { AutoRecoveryResult result; //Note: need to reload the storage location because it may have changed after the processing (eg, tier migration) IList<StudyStorageLocation> storageLocations = StudyStorageLocation.FindStorageLocations(StudyStorage.Load(item.StudyStorageKey)); // storageLocations cannot be null for this operation Platform.CheckForNullReference(storageLocations, "storageLocations"); Platform.CheckTrue(storageLocations.Count >= 1, "storageLocations.Count>=1"); StudyStorageLocation storageLocation = storageLocations[0]; Study study = storageLocation.LoadStudy(ServerExecutionContext.Current.PersistenceContext); Platform.Log(LogLevel.Info, "{4} failed. Reason:{5}. Attempting to perform auto-recovery for Study:{0}, A#:{1}, Patient:{2}, ID:{3}", study.StudyInstanceUid, study.AccessionNumber, study.PatientsName, study.PatientId, item.WorkQueueTypeEnum.ToString(), reason); StudyXml studyXml = storageLocation.LoadStudyXml(); Platform.CheckForNullReference(studyXml, "studyXml does not exist"); // Do a secondary check on the filesystem vs. the Study Xml. // If these match, then the DB is just update to reflect the valid counts. // If they don't match, a Reprocess entry is inserted into the WorkQueue. String studyFolder = storageLocation.GetStudyPath(); long fileCounter = DirectoryUtility.Count(studyFolder, "*.dcm", true, null); // cache these values to avoid looping again int numStudyRelatedSeriesInXml = studyXml.NumberOfStudyRelatedSeries; int numStudyRelatedInstancesInXml = studyXml.NumberOfStudyRelatedInstances; if (fileCounter != numStudyRelatedInstancesInXml) { // reprocess the study Log(LogLevel.Info, "AUTO-RECOVERY", "# of study related instances in study Xml ({0}) appears incorrect. Study needs to be reprocessed.", numStudyRelatedInstancesInXml); StudyReprocessor reprocessor = new StudyReprocessor(); String reprocessReason = String.Format("Auto-recovery from {0}. {1}", item.WorkQueueTypeEnum, reason); Model.WorkQueue reprocessEntry = reprocessor.ReprocessStudy(reprocessReason, storageLocation, Platform.Time); result = new AutoRecoveryResult { Successful = reprocessEntry!=null, ReprocessWorkQueueEntry=reprocessEntry }; return result; } Log(LogLevel.Info, "AUTO-RECOVERY", "# of study related instances in study Xml ({0}) appears correct. Update database based on study xml", numStudyRelatedInstancesInXml); // update the counts in db to match the study xml // Update count for each series IDictionary<string, Series> seriesList = storageLocation.Study.Series; foreach (Series series in seriesList.Values) { SeriesXml seriesXml = studyXml[series.SeriesInstanceUid]; if (seriesXml != null) { int numInstancesInSeriesXml = seriesXml.NumberOfSeriesRelatedInstances; if (numInstancesInSeriesXml != series.NumberOfSeriesRelatedInstances) { // Update the count in the series table. Assuming the stored procedure // will also update the count in the Study/Patient tables based on // the new value. Log(LogLevel.Info, "AUTO-RECOVERY", "Update series in the db. UID:{0}, #Instance:{1}==>{2}", series.SeriesInstanceUid, series.NumberOfSeriesRelatedInstances, numInstancesInSeriesXml); using (IUpdateContext updateContext = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush)) { ISetSeriesRelatedInstanceCount broker = updateContext.GetBroker<ISetSeriesRelatedInstanceCount>(); SetSeriesRelatedInstanceCountParameters criteria = new SetSeriesRelatedInstanceCountParameters(storageLocation.GetKey(), series.SeriesInstanceUid) { SeriesRelatedInstanceCount = numInstancesInSeriesXml }; if (!broker.Execute(criteria)) { throw new ApplicationException("Unable to update series related instance count in db"); } updateContext.Commit(); } } } else { // TODO: series in the db doesn't exist in the xml... the series was deleted from the study? // For now we just reprocess the study. Can we delete the series? If so, we need to take care of the counts. Log(LogLevel.Info, "AUTO-RECOVERY", "Found series in the db which does not exist in the study xml. Force to reprocess the study."); StudyReprocessor reprocessor = new StudyReprocessor(); String reprocessReason = String.Format("Auto-recovery from {0}. {1}", item.WorkQueueTypeEnum, reason); Model.WorkQueue reprocessEntry = reprocessor.ReprocessStudy(reprocessReason, storageLocation, Platform.Time); result = new AutoRecoveryResult { Successful = reprocessEntry != null, ReprocessWorkQueueEntry = reprocessEntry }; return result; } } if (numStudyRelatedSeriesInXml != storageLocation.Study.NumberOfStudyRelatedSeries || numStudyRelatedInstancesInXml != storageLocation.Study.NumberOfStudyRelatedInstances) { Log(LogLevel.Info, "AUTO-RECOVERY", "Updating study related series and instance counts in the db. #Series: {0} ==> {1}. #Instances: {2}==>{3}", storageLocation.Study.NumberOfStudyRelatedSeries, numStudyRelatedSeriesInXml, storageLocation.Study.NumberOfStudyRelatedInstances, numStudyRelatedInstancesInXml); using (IUpdateContext updateContext = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush)) { var broker = updateContext.GetBroker<ISetStudyRelatedInstanceCount>(); var criteria = new SetStudyRelatedInstanceCountParameters(storageLocation.GetKey()) { StudyRelatedSeriesCount = numStudyRelatedSeriesInXml, StudyRelatedInstanceCount = numStudyRelatedInstancesInXml }; if (!broker.Execute(criteria)) { throw new ApplicationException("Unable to update study related instance count in db"); } updateContext.Commit(); } } Log(LogLevel.Info, "AUTO-RECOVERY", "Object count in the db have been corrected."); result = new AutoRecoveryResult { Successful = true }; return result; }
public bool ReprocessWorkQueueItem(WorkQueue item) { // #10620: Get a list of remaining WorkQueueUids which need to be reprocess // Note: currently only WorkQueueUIDs in failed StudyProcess will be reprocessed var remainingWorkQueueUidPaths = item.GetAllWorkQueueUidPaths(); IPersistentStore store = PersistentStoreRegistry.GetDefaultStore(); using (IUpdateContext ctx = store.OpenUpdateContext(UpdateContextSyncMode.Flush)) { // delete current workqueue IWorkQueueUidEntityBroker uidBroker = ctx.GetBroker<IWorkQueueUidEntityBroker>(); WorkQueueUidSelectCriteria criteria = new WorkQueueUidSelectCriteria(); criteria.WorkQueueKey.EqualTo(item.GetKey()); if (uidBroker.Delete(criteria) >= 0) { IWorkQueueEntityBroker workQueueBroker = ctx.GetBroker<IWorkQueueEntityBroker>(); if (workQueueBroker.Delete(item.GetKey())) { IList<StudyStorageLocation> locations = item.LoadStudyLocations(ctx); if (locations!=null && locations.Count>0) { StudyReprocessor reprocessor = new StudyReprocessor(); String reason = String.Format("User reprocesses failed {0}", item.WorkQueueTypeEnum); WorkQueue reprocessEntry = reprocessor.ReprocessStudy(ctx, reason, locations[0], remainingWorkQueueUidPaths, Platform.Time); if (reprocessEntry!=null) ctx.Commit(); return reprocessEntry!=null; } } } } return false; }
private void ReprocessStudy(StudyStorageLocation restoredLocation, string reason) { StudyReprocessor reprocessor = new StudyReprocessor(); String reprocessReason = String.Format("Restore Validation Error: {0}", reason); reprocessor.ReprocessStudy(reprocessReason, restoredLocation, Platform.Time); string message = string.Format("Study {0} has been restored but failed the validation. Reprocess Study has been triggerred. Reason for validation failure: {1}", restoredLocation.StudyInstanceUid, reason); Platform.Log(LogLevel.Warn, message); ServerPlatform.Alert(AlertCategory.Application, AlertLevel.Informational, "Restore", 0, null, TimeSpan.Zero, message); }