/// <summary> /// Gets the <see cref="StudyStorageLocation"/> for the study associated with the specified <see cref="WorkQueue"/> item. /// </summary> /// <param name="item"></param> /// <returns></returns> public static StudyStorageLocation GetLoadStorageLocation(WorkQueue item) { var select = HttpContext.Current.GetSharedPersistentContext().GetBroker<IQueryStudyStorageLocation>(); var parms = new StudyStorageLocationQueryParameters(); parms.StudyStorageKey = item.StudyStorageKey; IList<StudyStorageLocation> storages = select.Find(parms); if (storages == null || storages.Count == 0) { Platform.Log(LogLevel.Error, "Unable to find storage location for WorkQueue item: {0}", item.Key.ToString()); throw new ApplicationException("Unable to find storage location for WorkQueue item."); } if (storages.Count > 1) { Platform.Log(LogLevel.Warn, "WorkQueueController:LoadWritableStorageLocation: multiple study storage found for work queue item {0}", item.Key.Key); } return storages[0]; }
protected override void OnExecute(CommandProcessor theProcessor, IUpdateContext updateContext) { var insert = updateContext.GetBroker<IInsertWorkQueue>(); var parms = new InsertWorkQueueParameters { WorkQueueTypeEnum = WorkQueueTypeEnum.StudyProcess, StudyStorageKey = _storageLocation.GetKey(), ServerPartitionKey = _storageLocation.ServerPartitionKey, SeriesInstanceUid = _message.DataSet[DicomTags.SeriesInstanceUid].GetString(0, String.Empty), SopInstanceUid = _message.DataSet[DicomTags.SopInstanceUid].GetString(0, String.Empty), ScheduledTime = Platform.Time, WorkQueueGroupID = _uidGroupId }; if (_duplicate) { parms.Duplicate = _duplicate; parms.Extension = _extension; parms.UidGroupID = _uidGroupId; } _insertedWorkQueue = insert.FindOne(parms); if (_insertedWorkQueue == null) throw new ApplicationException("UpdateWorkQueueCommand failed"); }
/// <summary> /// Gets the <see cref="StudyStorageLocation"/> for the study associated with the specified <see cref="WorkQueue"/> item. /// </summary> /// <param name="item"></param> /// <returns></returns> static public String GetLoadDuplicateStorageLocation(WorkQueue item) { XmlDocument document = item.Data; return document.ToString(); }
public WorkQueueProcessDuplicateSop(WorkQueue workQueue) { SetKey(workQueue.GetKey()); Data = workQueue.Data; ExpirationTime = workQueue.ExpirationTime; FailureCount = workQueue.FailureCount; FailureDescription = workQueue.FailureDescription; InsertTime = workQueue.InsertTime; ProcessorID = workQueue.ProcessorID; ScheduledTime = workQueue.ScheduledTime; ServerPartitionKey = workQueue.ServerPartitionKey; StudyHistoryKey = workQueue.StudyHistoryKey; StudyStorageKey = workQueue.StudyStorageKey; WorkQueuePriorityEnum = workQueue.WorkQueuePriorityEnum; WorkQueueStatusEnum = workQueue.WorkQueueStatusEnum; WorkQueueTypeEnum = workQueue.WorkQueueTypeEnum; _queueData = (ProcessDuplicateQueueEntryQueueData)_serializer.Deserialize(new XmlNodeReader(workQueue.Data.DocumentElement)); }
/// <summary> /// Constructor. /// </summary> /// <param name="thePartition"></param> /// <param name="location"></param> /// <param name="thePatient"></param> /// <param name="theStudy"></param> public StudyEditor(ServerPartition thePartition, StudyStorageLocation location, Patient thePatient, Study theStudy, WorkQueue workQueue) { FailureReason = string.Empty; Platform.CheckForNullReference(thePartition, "thePartition"); Platform.CheckForNullReference(location, "location"); Platform.CheckForNullReference(thePatient, "thePatient"); Platform.CheckForNullReference(theStudy, "theStudy"); ServerPartition = thePartition; StorageLocation = location; Patient = thePatient; Study = theStudy; _workQueue = workQueue; // Scrub for invalid characters that may cause a failure when the Xml is generated for the history Patient.PatientId = XmlUtils.XmlCharacterScrub(Patient.PatientId); Patient.PatientsName = XmlUtils.XmlCharacterScrub(Patient.PatientsName); Study.StudyDescription = XmlUtils.XmlCharacterScrub(Study.StudyDescription); Study.ReferringPhysiciansName = XmlUtils.XmlCharacterScrub(Study.ReferringPhysiciansName); Study.PatientId = XmlUtils.XmlCharacterScrub(Study.PatientId); Study.PatientsName = XmlUtils.XmlCharacterScrub(Study.PatientsName); }
public static WorkQueue Insert(IUpdateContext update, WorkQueue entity) { var broker = update.GetBroker<IWorkQueueEntityBroker>(); var updateColumns = new WorkQueueUpdateColumns(); updateColumns.ServerPartitionKey = entity.ServerPartitionKey; updateColumns.StudyStorageKey = entity.StudyStorageKey; updateColumns.WorkQueueTypeEnum = entity.WorkQueueTypeEnum; updateColumns.WorkQueueStatusEnum = entity.WorkQueueStatusEnum; updateColumns.WorkQueuePriorityEnum = entity.WorkQueuePriorityEnum; updateColumns.FailureCount = entity.FailureCount; updateColumns.ScheduledTime = entity.ScheduledTime; updateColumns.InsertTime = entity.InsertTime; updateColumns.LastUpdatedTime = entity.LastUpdatedTime; updateColumns.FailureDescription = entity.FailureDescription; updateColumns.Data = entity.Data; updateColumns.ExternalRequestQueueKey = entity.ExternalRequestQueueKey; updateColumns.ProcessorID = entity.ProcessorID; updateColumns.GroupID = entity.GroupID; updateColumns.ExpirationTime = entity.ExpirationTime; updateColumns.DeviceKey = entity.DeviceKey; updateColumns.StudyHistoryKey = entity.StudyHistoryKey; WorkQueue newEntity = broker.Insert(updateColumns); return newEntity; }
static public WorkQueue Insert(IUpdateContext update, WorkQueue entity) { var broker = update.GetBroker<IWorkQueueEntityBroker>(); var updateColumns = new WorkQueueUpdateColumns(); updateColumns.ServerPartitionKey = entity.ServerPartitionKey; updateColumns.StudyStorageKey = entity.StudyStorageKey; updateColumns.WorkQueueTypeEnum = entity.WorkQueueTypeEnum; updateColumns.WorkQueueStatusEnum = entity.WorkQueueStatusEnum; updateColumns.WorkQueuePriorityEnum = entity.WorkQueuePriorityEnum; updateColumns.FailureCount = entity.FailureCount; updateColumns.ScheduledTime = entity.ScheduledTime; updateColumns.InsertTime = entity.InsertTime; updateColumns.LastUpdatedTime = entity.LastUpdatedTime; updateColumns.FailureDescription = entity.FailureDescription; updateColumns.Data = entity.Data; updateColumns.ExternalRequestQueueKey = entity.ExternalRequestQueueKey; updateColumns.ProcessorID = entity.ProcessorID; updateColumns.GroupID = entity.GroupID; updateColumns.ExpirationTime = entity.ExpirationTime; updateColumns.DeviceKey = entity.DeviceKey; updateColumns.StudyHistoryKey = entity.StudyHistoryKey; WorkQueue newEntity = broker.Insert(updateColumns); return newEntity; }
public StudyProcessorContext(StudyStorageLocation storageLocation) { Platform.CheckForNullReference(storageLocation, "storageLocation"); _storageLocation = storageLocation; _workQueue = null; }
protected override void OnExecute(CommandProcessor theProcessor, IUpdateContext updateContext) { var insert = updateContext.GetBroker<IInsertWorkQueue>(); var parms = new InsertWorkQueueParameters { WorkQueueTypeEnum = WorkQueueTypeEnum.StudyProcess, StudyStorageKey = _storageLocation.GetKey(), ServerPartitionKey = _storageLocation.ServerPartitionKey, SeriesInstanceUid = _message.DataSet[DicomTags.SeriesInstanceUid].GetString(0, String.Empty), SopInstanceUid = _message.DataSet[DicomTags.SopInstanceUid].GetString(0, String.Empty), ScheduledTime = Platform.Time, }; if (_priority != null) parms.WorkQueuePriorityEnum = _priority; if (_data != null) { parms.WorkQueueData = ImageServerSerializer.SerializeWorkQueueDataToXmlDocument(_data); } if (_request != null) { parms.ExternalRequestQueueKey = _request.Key; } if (_uidData != null) { parms.WorkQueueUidData = _uidData; parms.Extension = _uidData.Extension; parms.UidGroupID = _uidData.GroupId; parms.WorkQueueGroupID = _uidData.GroupId; } if (_duplicate) { parms.Duplicate = _duplicate; } _insertedWorkQueue = insert.FindOne(parms); if (_insertedWorkQueue == null) throw new ApplicationException("UpdateWorkQueueCommand failed"); }
static public WorkQueue Insert(WorkQueue entity) { using (var update = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush)) { WorkQueue newEntity = Insert(update, entity); update.Commit(); return newEntity; } }
static public bool CanReprocess(WorkQueue item) { return item.WorkQueueStatusEnum == WorkQueueStatusEnum.Failed && item.WorkQueueTypeEnum == WorkQueueTypeEnum.StudyProcess; }
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; }
/// <summary> /// Returns a value indicating whether the specified <see cref="WorkQueue"/> can be manually reset. /// </summary> /// <param name="item"></param> /// <returns></returns> static public bool CanReset(WorkQueue item) { if (item == null) return false; return /* failed item */ item.WorkQueueStatusEnum == WorkQueueStatusEnum.Failed /* nobody claimed it */ || (item.WorkQueueStatusEnum == WorkQueueStatusEnum.InProgress && String.IsNullOrEmpty(item.ProcessorID)) /* allow reset "stuck" items (except items that are InProgress)*/ || (!item.WorkQueueStatusEnum.Equals(WorkQueueStatusEnum.InProgress) && !WorkQueueHelper.IsActiveWorkQueue(item)); }
/// <summary> /// Returns a value indicating whether the specified <see cref="WorkQueue"/> can be manually deleted from the queue. /// </summary> /// <param name="item"></param> /// <returns></returns> static public bool CanDelete(WorkQueue item) { if (item == null) return false; return /* failed item */ item.WorkQueueStatusEnum == WorkQueueStatusEnum.Failed /* completed item */ || (item.WorkQueueStatusEnum == WorkQueueStatusEnum.Completed) /* nobody claimed it */ || (item.WorkQueueStatusEnum == WorkQueueStatusEnum.InProgress && String.IsNullOrEmpty(item.ProcessorID)) // allow deletes of some pending entries || (item.WorkQueueStatusEnum != WorkQueueStatusEnum.InProgress && item.WorkQueueTypeEnum == WorkQueueTypeEnum.WebMoveStudy) || (item.WorkQueueStatusEnum != WorkQueueStatusEnum.InProgress && item.WorkQueueTypeEnum == WorkQueueTypeEnum.WebEditStudy) || (item.WorkQueueStatusEnum != WorkQueueStatusEnum.InProgress && item.WorkQueueTypeEnum == WorkQueueTypeEnum.AutoRoute) || (item.WorkQueueStatusEnum != WorkQueueStatusEnum.InProgress && item.WorkQueueTypeEnum == WorkQueueTypeEnum.WebDeleteStudy) /* allow deletes of "stuck" items (except items that are InProgress)*/ || (!item.WorkQueueStatusEnum.Equals(WorkQueueStatusEnum.InProgress) && !WorkQueueHelper.IsActiveWorkQueue(item)); }
/// <summary> /// Returns a boolean indicating whether the entry is still "active" /// </summary> /// <remarks> /// </remarks> static public bool IsActiveWorkQueue(WorkQueue item) { // The following code assumes InactiveWorkQueueMinTime is set appropirately if (item.WorkQueueStatusEnum.Equals(WorkQueueStatusEnum.Failed)) return false; if (item.WorkQueueStatusEnum.Equals(WorkQueueStatusEnum.Pending) || item.WorkQueueStatusEnum.Equals(WorkQueueStatusEnum.Idle)) { // Assuming that if the entry is picked up and rescheduled recently (the ScheduledTime would have been updated), // the item is inactive if its ScheduledTime still indicated it was scheduled long time ago. // Note: this logic still works if the entry has never been processed (new). It will be // considered as "inactive" if it was scheduled long time ago and had never been updated. DateTime lastActiveTime = item.LastUpdatedTime.GetValueOrDefault(item.ScheduledTime); return (Platform.Time - lastActiveTime < Settings.Default.InactiveWorkQueueMinTime); } else if (item.WorkQueueStatusEnum.Equals(WorkQueueStatusEnum.InProgress)) { if (String.IsNullOrEmpty(item.ProcessorID)) { // This is a special case, the item is not assigned but is set to InProgress. // It's definitely stuck cause it won't be picked up by any servers. return false; } // TODO: Need more elaborate logic to detect if it's stuck when the status is InProgress. // Ideally, we can assume item is stuck if it has not been updated for a while. // Howerver, some operations were designed to process everything in a single run // instead of batches.One example is the StudyProcess, research studies may take days to process // and the item stays in "InProgress" for the entire period without any update // (eventhough the WorkQueueUid records are removed) // For now, we assume it's stucked if it is not updated for long time. if (item.ScheduledTime < Platform.Time - Settings.Default.InactiveWorkQueueMinTime) return false; } return true; }
/// <summary> /// Returns a value indicating whether the specified <see cref="WorkQueue"/> can be manually rescheduled. /// </summary> /// <param name="item"></param> /// <returns></returns> static public bool CanReschedule(WorkQueue item) { if (item == null) return false; return // it's pending item.WorkQueueStatusEnum == WorkQueueStatusEnum.Pending // it's idle || item.WorkQueueStatusEnum == WorkQueueStatusEnum.Idle; }
public static WorkQueue Load(IPersistenceContext read, ServerEntityKey key) { var broker = read.GetBroker<IWorkQueueEntityBroker>(); WorkQueue theObject = broker.Load(key); return theObject; }
/// <summary> /// Helper method to return the path to the folder containing the duplicate images (in the Reconcile folder) /// </summary> /// <param name="storageLocation"></param> /// <param name="queueItem"></param> /// <returns></returns> public static string GetDuplicateGroupPath(StudyStorageLocation storageLocation, WorkQueue queueItem) { string path = Path.Combine(storageLocation.FilesystemPath, storageLocation.PartitionFolder); path = Path.Combine(path, ServerPlatform.ReconcileStorageFolder); path = Path.Combine(path, queueItem.GroupID); return path; }
public UpdateStudyCommand(ServerPartition partition, StudyStorageLocation studyLocation, IList<BaseImageLevelUpdateCommand> imageLevelCommands, ServerRuleApplyTimeEnum applyTime, WorkQueue workQueue) : base("Update existing study") { _partition = partition; _oldStudyLocation = studyLocation; _commands = imageLevelCommands; _workQueue = workQueue; _statistics = new UpdateStudyStatistics(_oldStudyLocation.StudyInstanceUid); // Load the engine for editing rules. _rulesEngine = new ServerRulesEngine(applyTime, _partition.Key); if (applyTime.Equals(ServerRuleApplyTimeEnum.SopProcessed)) _rulesEngine.AddIncludeType(ServerRuleTypeEnum.AutoRoute); _rulesEngine.Load(); }
/// <summary> /// Create Duplicate SIQ Entry /// </summary> /// <param name="file"></param> /// <param name="location"></param> /// <param name="sourcePath"></param> /// <param name="queue"></param> /// <param name="uid"></param> /// <param name="data"></param> public static void CreateDuplicateSIQEntry(DicomFile file, StudyStorageLocation location, string sourcePath, WorkQueue queue, WorkQueueUid uid, StudyProcessWorkQueueData data) { Platform.Log(LogLevel.Info, "Creating Work Queue Entry for duplicate..."); String uidGroup = queue.GroupID ?? queue.GetKey().Key.ToString(); using (var commandProcessor = new ServerCommandProcessor("Insert Work Queue entry for duplicate")) { commandProcessor.AddCommand(new FileDeleteCommand(sourcePath, true)); var sopProcessingContext = new SopInstanceProcessorContext(commandProcessor, location, uidGroup); DicomProcessingResult result = Process(sopProcessingContext, file, data); if (!result.Successful) { FailUid(uid, true); return; } commandProcessor.AddCommand(new DeleteWorkQueueUidCommand(uid)); if (!commandProcessor.Execute()) { Platform.Log(LogLevel.Error, "Unexpected error when creating duplicate study integrity queue entry: {0}", commandProcessor.FailureReason); FailUid(uid, true); } } }
/// <summary> /// Constructs an instance of <see cref="WorkQueueSummary"/> based on a <see cref="WorkQueue"/> object. /// </summary> /// <param name="item"></param> /// <returns></returns> /// <remark> /// /// </remark> private WorkQueueSummary CreateWorkQueueSummary(WorkQueue item) { WorkQueueSummary summary = new WorkQueueSummary { TheWorkQueueItem = item, ThePartition = Partition }; // Fetch the patient info: StudyStorageAdaptor ssAdaptor = new StudyStorageAdaptor(); StudyStorage storages = ssAdaptor.Get(item.StudyStorageKey); if (storages == null) { summary.PatientId = "N/A"; summary.PatientsName = "N/A"; return summary; } StudyAdaptor studyAdaptor = new StudyAdaptor(); StudySelectCriteria studycriteria = new StudySelectCriteria(); studycriteria.StudyInstanceUid.EqualTo(storages.StudyInstanceUid); studycriteria.ServerPartitionKey.EqualTo(item.ServerPartitionKey); IList<Study> studyList = studyAdaptor.Get(studycriteria); if (studyList == null || studyList.Count == 0) { summary.PatientId = "N/A"; summary.PatientsName = "N/A"; } else { summary.PatientId = studyList[0].PatientId; summary.PatientsName = studyList[0].PatientsName; } if (item.WorkQueueTypeEnum == WorkQueueTypeEnum.WebMoveStudy || item.WorkQueueTypeEnum == WorkQueueTypeEnum.AutoRoute) { DeviceDataAdapter deviceAdaptor = new DeviceDataAdapter(); Device dest = deviceAdaptor.Get(item.DeviceKey); summary.Notes = String.Format("Destination AE : {0}", dest.AeTitle); if (item.FailureDescription != null) { summary.FullDescription = String.Format("{0}, {1}", summary.Notes, item.FailureDescription); //Set the FullDescription for the Tooltip in the GUI summary.Notes = summary.FullDescription.Length > 60 ? summary.FullDescription.Substring(0, 60) : summary.FullDescription; } } else if (item.FailureDescription != null) { // This used to only be shown when the status was "Failed" for a // queue entry. We now show it any time there's if (item.FailureDescription.Length > 60) { summary.Notes = item.FailureDescription.Substring(0, 60); summary.Notes += " ..."; summary.FullDescription = item.FailureDescription; //Set the FullDescription for the Tooltip in the GUI } else summary.Notes = item.FailureDescription; } summary.RequiresAttention = item.WorkQueueStatusEnum.Equals(WorkQueueStatusEnum.Failed) || !ServerPlatform.IsActiveWorkQueue(item); return summary; }