public FailedCacheFetchRequestProvider(ICacheProgress cacheProgress, int batchSize = 50)
        {
            _cacheProgress = cacheProgress;
            _batchSize     = batchSize;

            Current = null;
        }
示例#2
0
 public TestCacheChunk(DateTime fetchDate)
 {
     Request = new CacheFetchRequest(null, fetchDate)
     {
         ChunkPeriod = new TimeSpan(1, 0, 0)
     };
 }
示例#3
0
        public override TestCacheChunk DoGetChunk(ICacheFetchRequest request, IDataLoadEventListener listener, GracefulCancellationToken cancellationToken)
        {
            var c = new TestCacheChunk(Request.Start);

            listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "!!" + request.Start.ToString("g")));
            return(c);
        }
        /// <summary>
        /// Returns the next <see cref="ICacheFetchRequest"/> based on the <see cref="Current"/>
        /// </summary>
        /// <param name="listener"></param>
        /// <returns></returns>
        public ICacheFetchRequest GetNext(IDataLoadEventListener listener)
        {
            if (_initialRequest == null)
            {
                return(Current = _initialRequest = CreateInitialRequest());
            }

            return(Current = CreateNext());
        }
        public override SMIDataChunk DoGetChunk(ICacheFetchRequest request, IDataLoadEventListener listener, GracefulCancellationToken cancellationToken)
        {
            listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, $"ProcessBasedCacheSource version is {typeof(ProcessBasedCacheSource).Assembly.GetName().Version}.  Assembly is {typeof(ProcessBasedCacheSource).Assembly} "));

            // Where we are putting the files
            var cacheDir    = new LoadDirectory(Request.CacheProgress.LoadProgress.LoadMetadata.LocationOfFlatFiles).Cache;
            var cacheLayout = new SMICacheLayout(cacheDir, new SMICachePathResolver("ALL"));

            Chunk = new SMIDataChunk(Request)
            {
                FetchDate = Request.Start,
                Modality  = "ALL",
                Layout    = cacheLayout
            };

            var workingDirectory = cacheLayout.GetLoadCacheDirectory(listener);

            listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Working directory is:" + workingDirectory));
            listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Fetch Start is:" + request.Start));
            listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Fetch End is:" + request.End));

            listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Command is:" + Command));
            listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Args template is:" + Args));
            listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Datetime format is:" + TimeFormat));


            string args = Args
                          .Replace("%s", request.Start.ToString(TimeFormat))
                          .Replace("%e", request.End.ToString(TimeFormat))
                          .Replace("%d", workingDirectory.FullName);

            listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Args resolved is:" + args));

            using (var p = new Process())
            {
                p.StartInfo.FileName               = Command;
                p.StartInfo.Arguments              = args;
                p.StartInfo.UseShellExecute        = false;
                p.StartInfo.RedirectStandardOutput = true;
                p.OutputDataReceived              += (sender, a) => listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, a.Data));

                p.Start();
                p.BeginOutputReadLine();

                p.WaitForExit();

                listener.OnNotify(this, new NotifyEventArgs(p.ExitCode == 0 ? ProgressEventType.Information : ProgressEventType.Warning, "Process exited with code " + p.ExitCode));

                if (p.ExitCode != 0 && ThrowOnNonZeroExitCode)
                {
                    throw new Exception("Process exited with code " + p.ExitCode);
                }
            }

            return(Chunk);
        }
示例#6
0
        public override ICacheChunk DoGetChunk(ICacheFetchRequest request, IDataLoadEventListener listener, GracefulCancellationToken cancellationToken)
        {
            //Data is never available for download
            if (runs < 10)
            {
                runs++;

                return(new DoNothingCacheChunk(CatalogueRepository)
                {
                    RunIteration = runs
                });
            }

            return(null);
        }
        public ICacheFetchRequest GetNext(IDataLoadEventListener listener)
        {
            // If we haven't provided one, give out _initialRequest
            if (Current == null)
            {
                Current = _initialRequest;
            }
            else
            {
                Current = Current.GetNext();

                // We have provided requests for the whole time period
                if (Current.Start > _endDateInclusive)
                {
                    return(null);
                }
            }

            return(Current);
        }
        public ICacheFetchRequest GetNext(IDataLoadEventListener listener)
        {
            // If we haven't provided one, give out _initialRequest
            if (Current == null)
            {
                Current = _initialRequest;
            }
            else
            {
                Current = Current.GetNext();
                // We have provided requests for more than one day
                if (Current.Start >= _initialRequest.Start.AddDays(1))
                {
                    return(null);
                }
            }

            // Otherwise we have provided our request so signal there is none left
            return(Current);
        }
        /// <summary>
        ///
        /// </summary>
        /// <returns>Next CacheFetchRequest or null if there are no further request failures to process</returns>
        public ICacheFetchRequest GetNext(IDataLoadEventListener listener)
        {
            if (!_failuresToProvide.Any())
            {
                listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Getting next batch of request failures from database."));
                GetNextBatchFromDatabase();
                listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Fetched " + _failuresToProvide.Count + " failures from database."));

                // If there are still no failures in the queue then we're done
                if (!_failuresToProvide.Any())
                {
                    return(null);
                }
            }

            // Create a new CacheFetchRequest from the failure
            var cacheFetchFailure = _failuresToProvide.Dequeue();

            Current = new CacheFetchRequest(cacheFetchFailure, _cacheProgress);
            return(Current);
        }
示例#10
0
        public override TestDataWriterChunk DoGetChunk(ICacheFetchRequest request, IDataLoadEventListener listener, GracefulCancellationToken cancellationToken)
        {
            // don't load anything for today onwards
            var today = DateTime.Now.Subtract(DateTime.Now.TimeOfDay);

            if (Request.Start > today)
            {
                return(null);
            }

            DateTime currentDay = Request.Start;

            List <FileInfo> toReturn = new List <FileInfo>();

            while (currentDay <= Request.End)
            {
                toReturn.Add(GetFileForDay(currentDay));
                currentDay = currentDay.AddDays(1);
            }

            return(new TestDataWriterChunk(Request, toReturn.ToArray()));
        }
示例#11
0
        /// <summary>
        /// Enforces behaviour required for logging unsuccessful cache requests and providing implementation-independent checks, so that the plugin author
        /// doesn't need to remember to call Request[Succeeded|Failed] or do general checks.  Plugin author provides implementation-specific caching in
        /// the 'DoGetChunk' function.
        /// </summary>
        /// <param name="listener"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public virtual T GetChunk(IDataLoadEventListener listener, GracefulCancellationToken cancellationToken)
        {
            Request = RequestProvider.GetNext(listener);

            // If GetNext returns null, there are no further failures to process and we're done
            if (Request == null)
            {
                listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "The RequestProvider has no more requests to provide (RequestProvider.GetNext returned null)"));
                return(null);
            }

            if (Request.CacheProgress == null)
            {
                throw new InvalidOperationException("The request has no CacheProgress item (in this case to determine when the lag period begins)");
            }

            // Check if we will stray into the lag period with this fetch and if so signal we are finished
            var cacheLagPeriod = Request.CacheProgress.GetCacheLagPeriod();

            if (cacheLagPeriod != null && cacheLagPeriod.TimeIsWithinPeriod(Request.End))
            {
                listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "The Request is for a time within the Cache Lag Period. This means we are up-to-date and can stop now."));
                return(null);
            }

            Chunk = DoGetChunk(Request, listener, cancellationToken);

            if (Chunk != null && Chunk.Request == null && Request != null)
            {
                listener.OnNotify(this,
                                  new NotifyEventArgs(ProgressEventType.Error,
                                                      "DoGetChunk completed and set a Chunk Successfully but the Chunk.Request was null.  Try respecting the Request property in your class when creating your Chunk."));
            }

            return(Chunk);
        }
示例#12
0
        public override SMIDataChunk DoGetChunk(ICacheFetchRequest cacheRequest, IDataLoadEventListener listener, GracefulCancellationToken cancellationToken)
        {
            #region assigns
            var dicomConfiguration  = GetConfiguration();
            var requestSender       = new DicomRequestSender(dicomConfiguration, listener);
            var dateFrom            = Request.Start;
            var dateTo              = Request.End;
            var hasTransferTimedOut = false;
            CachingSCP.LocalAet = LocalAETitle;
            CachingSCP.Listener = listener;

            if (PatientIdWhitelistColumnInfo != null && !IgnoreWhiteList)
            {
                GetWhitelist(listener);
            }


            //temp dir
            var cacheDir    = new LoadDirectory(Request.CacheProgress.LoadProgress.LoadMetadata.LocationOfFlatFiles).Cache;
            var cacheLayout = new SMICacheLayout(cacheDir, new SMICachePathResolver(Modality));


            Chunk = new SMIDataChunk(Request)
            {
                FetchDate = dateFrom,
                Modality  = Modality,
                Layout    = cacheLayout
            };
            //            IOrder order = new ItemsBasedOrder(dateFrom, dateTo, PlacementMode.PlaceThenFill,OrderLevel, listener);
            IOrder  order                = new HierarchyBasedOrder(dateFrom, dateTo, PlacementMode.PlaceThenFill, OrderLevel, listener);
            IPicker picker               = null;
            var     pickerFilled         = false;
            var     transferTimeOutTimer = new Timer(dicomConfiguration.TransferTimeOutInMilliseconds);
            transferTimeOutTimer.Elapsed += (source, eventArgs) =>
            {
                hasTransferTimedOut = true;
                listener.OnNotify(this,
                                  new NotifyEventArgs(ProgressEventType.Information, "Transfer Timeout Exception Generated"));
                throw new TimeoutException("Transfer Timeout Exception");
            };

            CachingSCP.OnEndProcessingCStoreRequest = (storeRequest, storeResponse) =>
            {
                var item = new Item(storeRequest);
                transferTimeOutTimer.Reset();
                if (picker != null)
                {
                    picker.Fill(item);
                    pickerFilled = picker.IsFilled();
                }
                SaveSopInstance(storeRequest, cacheLayout, listener);
                listener.OnNotify(this,
                                  new NotifyEventArgs(ProgressEventType.Debug,
                                                      "Stored sopInstance" + storeRequest.SOPInstanceUID.UID));
            };
            #endregion

            //helps with tyding up resources if we abort or through an exception and neatly avoids ->  Access to disposed closure
            using (var server = (DicomServer <CachingSCP>)DicomServer.Create <CachingSCP>(dicomConfiguration.LocalAetUri.Port))
            {
                try
                {
                    // Find a list of studies
                    #region Query

                    listener.OnNotify(this,
                                      new NotifyEventArgs(ProgressEventType.Information,
                                                          "Requesting Studies from " + dateFrom + " to " + dateTo));
                    var studyUids = new List <string>();
                    var request   = CreateStudyRequestByDateRangeForModality(dateFrom, dateTo, Modality);
                    request.OnResponseReceived += (req, response) =>
                    {
                        if (Filter(_whitelist, response))
                        {
                            studyUids.Add(response.Dataset.GetSingleValue <string>(DicomTag.StudyInstanceUID));
                        }
                    };
                    requestSender.ThrottleRequest(request, cancellationToken);
                    listener.OnNotify(this,
                                      new NotifyEventArgs(ProgressEventType.Debug,
                                                          "Total filtered studies for " + dateFrom + " to " + dateTo + "is " + studyUids.Count));
                    foreach (var studyUid in studyUids)
                    {
                        listener.OnNotify(this,
                                          new NotifyEventArgs(ProgressEventType.Debug,
                                                              "Sending series query for study" + studyUid));
                        var seriesUids = new List <string>();
                        request = CreateSeriesRequestByStudyUid(studyUid);
                        request.OnResponseReceived += (req, response) =>
                        {
                            if (response.Dataset == null)
                            {
                                return;
                            }
                            var seriesInstanceUID = response.Dataset.GetSingleValue <string>(DicomTag.SeriesInstanceUID);
                            if (seriesInstanceUID != null)
                            {
                                seriesUids.Add(seriesInstanceUID);
                            }
                        };
                        requestSender.ThrottleRequest(request, cancellationToken);
                        listener.OnNotify(this,
                                          new NotifyEventArgs(ProgressEventType.Debug,
                                                              "Total series for " + studyUid + "is " + seriesUids.Count));
                        foreach (var seriesUid in seriesUids)
                        {
                            listener.OnNotify(this,
                                              new NotifyEventArgs(ProgressEventType.Debug,
                                                                  "Sending image query for series" + seriesUid));
                            request = CreateSopRequestBySeriesUid(seriesUid);
                            int imageCount = 0;
                            request.OnResponseReceived += (req, response) =>
                            {
                                if (response.Dataset == null)
                                {
                                    return;
                                }

                                var sopUid    = response.Dataset.GetSingleValue <string>(DicomTag.SOPInstanceUID);
                                var patientId = response.Dataset.GetSingleValue <string>(DicomTag.PatientID);

                                if (sopUid != null && patientId != null)
                                {
                                    //Place order
                                    order.Place(patientId, studyUid, seriesUid, sopUid);
                                    imageCount++;
                                }
                            };
                            requestSender.ThrottleRequest(request, cancellationToken);
                            listener.OnNotify(this,
                                              new NotifyEventArgs(ProgressEventType.Debug,
                                                                  "Successfully finished image query for " + seriesUid + " Toal images in series = " + imageCount));
                        }
                        listener.OnNotify(this,
                                          new NotifyEventArgs(ProgressEventType.Debug,
                                                              "Successfully finished series query for " + studyUid));
                    }
                    listener.OnNotify(this,
                                      new NotifyEventArgs(ProgressEventType.Debug,
                                                          "Successfully finished query phase"));

                    #endregion
                    //go and get them
                    #region Retrieval

                    var transferStopwatch = new Stopwatch();
                    //start building request to fill orders
                    //get the picker - the for loop avoids sleeping after all the transfers have finished and attempting dequeue on empty queue
                    for (int delay = 0, transferTimerPollingPeriods;
                         order.HasNextPicker() && !hasTransferTimedOut;
                         delay = (int)(dicomConfiguration.TransferDelayFactor * transferTimerPollingPeriods * dicomConfiguration.TransferPollingInMilliseconds)
                                 + dicomConfiguration.TransferCooldownInMilliseconds
                         )
                    {
                        transferStopwatch.Restart();
                        //delay value in mills
                        if (delay != 0)
                        {
                            listener.OnNotify(this,
                                              new NotifyEventArgs(ProgressEventType.Information,
                                                                  "Transfers sleeping for " + delay / 1000 + "seconds"));
                            Task.Delay(delay, cancellationToken.AbortToken).Wait(cancellationToken.AbortToken);
                        }

                        //set this here prior to request
                        pickerFilled = false;
                        transferTimerPollingPeriods = 0;
                        //get next picker
                        picker = order.NextPicker();
                        //  A CMove will be performed if the storescp exists and this storescp is known to the QRSCP:
                        var cMoveRequest = picker.GetDicomCMoveRequest(LocalAETitle);

                        /* this won't work which means we cannot enforce (low) priority
                         * cMoveRequest.Priority=DicomPriority.Low;*/

                        cMoveRequest.OnResponseReceived += (requ, response) =>
                        {
                            if (response.Status.State == DicomState.Pending)
                            {
                                listener.OnNotify(this,
                                                  new NotifyEventArgs(ProgressEventType.Debug,
                                                                      "Request: " + requ.ToString() + "items remaining: " + response.Remaining));
                            }
                            else if (response.Status.State == DicomState.Success)
                            {
                                listener.OnNotify(this,
                                                  new NotifyEventArgs(ProgressEventType.Debug,
                                                                      "Request: " + requ.ToString() + "completed successfully"));
                            }
                            else if (response.Status.State == DicomState.Failure)
                            {
                                listener.OnNotify(this,
                                                  new NotifyEventArgs(ProgressEventType.Debug,
                                                                      "Request: " + requ.ToString() + "failed to download: " + response.Failures));
                            }
                        };

                        listener.OnProgress(this,
                                            new ProgressEventArgs(CMoveRequestToString(cMoveRequest),
                                                                  new ProgressMeasurement(picker.Filled(), ProgressType.Records, picker.Total()),
                                                                  transferStopwatch.Elapsed));
                        //do not use requestSender.ThrottleRequest(cMoveRequest, cancellationToken);
                        //TODO is there any need to throtttle this request given its lifetime
                        DicomClient client = new DicomClient();
                        requestSender.ThrottleRequest(cMoveRequest, client, cancellationToken);
                        transferTimeOutTimer.Reset();
                        while (!pickerFilled && !hasTransferTimedOut)
                        {
                            Task.Delay(dicomConfiguration.TransferPollingInMilliseconds, cancellationToken.AbortToken)
                            .Wait(cancellationToken.AbortToken);
                            transferTimerPollingPeriods++;
                        }
                        transferTimeOutTimer.Stop();
                        client.Release();
                        listener.OnProgress(this,
                                            new ProgressEventArgs(CMoveRequestToString(cMoveRequest),
                                                                  new ProgressMeasurement(picker.Filled(), ProgressType.Records, picker.Total()),
                                                                  transferStopwatch.Elapsed));
                    }

                    #endregion
                }
                finally
                {
                    server.Stop();
                }
            }
            return(Chunk);
        }
 public SingleDayCacheFetchRequestProvider(ICacheFetchRequest initialRequest)
 {
     Current         = null;
     _initialRequest = initialRequest;
 }
示例#14
0
        public override SMIDataChunk DoGetChunk(ICacheFetchRequest cacheRequest, IDataLoadEventListener listener, GracefulCancellationToken cancellationToken)
        {
            listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, $"PACSSource version is {typeof(PACSSource).Assembly.GetName().Version}.  Assembly is {typeof(PACSSource).Assembly} "));
            listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, $"Fo-Dicom version is {typeof(DicomClient).Assembly.GetName().Version}.  Assembly is {typeof(DicomClient).Assembly} "));

            var dicomConfiguration = GetConfiguration();
            var requestSender      = new DicomRequestSender(dicomConfiguration, listener);
            var dateFrom           = Request.Start;
            var dateTo             = Request.End;

            CachingSCP.LocalAet = LocalAETitle;
            CachingSCP.Listener = listener;

            if (PatientIdWhitelistColumnInfo != null && !IgnoreWhiteList)
            {
                GetWhitelist(listener);
            }

            //temp dir
            var cacheDir    = new LoadDirectory(Request.CacheProgress.LoadProgress.LoadMetadata.LocationOfFlatFiles).Cache;
            var cacheLayout = new SMICacheLayout(cacheDir, new SMICachePathResolver(Modality));

            Chunk = new SMIDataChunk(Request)
            {
                FetchDate = dateFrom,
                Modality  = Modality,
                Layout    = cacheLayout
            };

            ConcurrentBag <StudyToFetch> studiesToOrder = new ConcurrentBag <StudyToFetch>();

            CachingSCP.OnEndProcessingCStoreRequest = (storeRequest, storeResponse) =>
            {
                SaveSopInstance(storeRequest, cacheLayout, listener);
                listener.OnNotify(this,
                                  new NotifyEventArgs(ProgressEventType.Debug,
                                                      "Stored sopInstance" + storeRequest.SOPInstanceUID.UID));
            };

            //helps with tyding up resources if we abort or through an exception and neatly avoids ->  Access to disposed closure
            using (var server = (DicomServer <CachingSCP>)DicomServer.Create <CachingSCP>(dicomConfiguration.LocalAetUri.Port))
            {
                DicomClient client = new DicomClient(dicomConfiguration.RemoteAetUri.Host, dicomConfiguration.RemoteAetUri.Port, false, dicomConfiguration.LocalAetTitle, dicomConfiguration.RemoteAetTitle);

                try
                {
                    // Find a list of studies
                    #region Query

                    listener.OnNotify(this,
                                      new NotifyEventArgs(ProgressEventType.Information,
                                                          "Requesting Studies from " + dateFrom + " to " + dateTo));

                    var request = CreateStudyRequestByDateRangeForModality(dateFrom, dateTo, Modality);
                    request.OnResponseReceived += (req, response) =>
                    {
                        if (Filter(_whitelist, response))
                        {
                            studiesToOrder.Add(new StudyToFetch(response.Dataset.GetSingleValue <string>(DicomTag.StudyInstanceUID)));
                        }
                    };
                    requestSender.ThrottleRequest(request, client, cancellationToken.AbortToken);
                    listener.OnNotify(this,
                                      new NotifyEventArgs(ProgressEventType.Debug,
                                                          "Total filtered studies for " + dateFrom + " to " + dateTo + "is " + studiesToOrder.Count));
                    #endregion

                    //go and get them
                    #region Retrieval

                    var transferStopwatch = new Stopwatch();

                    StudyToFetch current;
                    int          consecutiveFailures = 0;

                    //While we have things to fetch
                    while (studiesToOrder.TryTake(out current))
                    {
                        transferStopwatch.Restart();
                        //delay value in mills
                        if (dicomConfiguration.TransferCooldownInMilliseconds != 0)
                        {
                            listener.OnNotify(this,
                                              new NotifyEventArgs(ProgressEventType.Information,
                                                                  "Transfers sleeping for " + dicomConfiguration.TransferCooldownInMilliseconds / 1000 + "seconds"));
                            Task.Delay(dicomConfiguration.TransferCooldownInMilliseconds, cancellationToken.AbortToken).Wait(cancellationToken.AbortToken);
                        }

                        bool done = false;

                        //Build fetch command that Study
                        var cMoveRequest = CreateCMoveByStudyUid(LocalAETitle, current.StudyUid, listener);

                        //Register callbacks
                        cMoveRequest.OnResponseReceived += (requ, response) =>
                        {
                            listener.OnNotify(this,
                                              new NotifyEventArgs(ProgressEventType.Debug,
                                                                  $"Got {response.Status.State} response for {requ}.  Items remaining {response.Remaining}"));

                            switch (response.Status.State)
                            {
                            case DicomState.Pending:
                            case DicomState.Warning:
                                // ignore
                                break;

                            case DicomState.Cancel:
                            case DicomState.Failure:
                                consecutiveFailures++;

                                if (current.RetryCount < MaxRetries)
                                {
                                    // put it back in the bag with a increased retry count
                                    current.RetryCount++;
                                    studiesToOrder.Add(current);
                                }

                                // final state
                                done = true;
                                break;

                            case DicomState.Success:
                                // final state
                                consecutiveFailures = 0;
                                done = true;
                                break;
                            }
                        };

                        //send the command to the server

                        //tell user what we are sending
                        listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, CMoveRequestToString(cMoveRequest, current.RetryCount + 1)));

                        //do not use requestSender.ThrottleRequest(cMoveRequest, cancellationToken);
                        //TODO is there any need to throtttle this request given its lifetime
                        requestSender.ThrottleRequest(cMoveRequest, client, cancellationToken.AbortToken);


                        //enforce a minimum timeout
                        var  swStudyTransfer     = Stopwatch.StartNew();
                        bool hasTransferTimedOut = false;

                        do
                        {
                            Task.Delay(Math.Max(100, dicomConfiguration.TransferPollingInMilliseconds), cancellationToken.AbortToken)
                            .Wait(cancellationToken.AbortToken);

                            hasTransferTimedOut = swStudyTransfer.ElapsedMilliseconds > dicomConfiguration.TransferTimeOutInMilliseconds;
                        }while(!done && !hasTransferTimedOut);

                        // Study has finished being fetched (or timed out)

                        if (hasTransferTimedOut)
                        {
                            listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Abandonning fetch of study " + current.StudyUid));
                        }

                        if (consecutiveFailures > 5)
                        {
                            throw new Exception("Too many consecutive failures, giving up");
                        }

                        // 1 failure = study not available, 2 failures = system is having a bad day?
                        if (consecutiveFailures > 1)
                        {
                            //wait 4 minutes then 6 minutes then 8 minutes, eventually server will start responding again?
                            int sleepFor = consecutiveFailures * 2 * 60_000;
                            listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Warning, $"Sleeping for {sleepFor}ms due to {consecutiveFailures} consecutive failures"));

                            Task.Delay(sleepFor, cancellationToken.AbortToken)
                            .Wait(cancellationToken.AbortToken);
                        }
                    }

                    #endregion
                }
                finally
                {
                    server.Stop();
                }
            }

            return(Chunk);
        }
示例#15
0
 /// <summary>
 /// Handles the current <paramref name="request"/> returning an appropriate <see cref="ICacheChunk"/> for the time range specified.
 /// </summary>
 /// <param name="request">The period of time we want to fetch</param>
 /// <param name="listener">For auditing progress during the fetch</param>
 /// <param name="cancellationToken">Indicates if user is trying to cancel the process</param>
 public abstract T DoGetChunk(ICacheFetchRequest request, IDataLoadEventListener listener, GracefulCancellationToken cancellationToken);
示例#16
0
 public TestDataWriterChunk(ICacheFetchRequest request, FileInfo[] files)
 {
     Request = request;
     Files   = files;
 }
示例#17
0
 public SMIDataChunk(ICacheFetchRequest request)
 {
     Request = request;
 }
示例#18
0
        public override SMIDataChunk DoGetChunk(ICacheFetchRequest cacheRequest, IDataLoadEventListener listener, GracefulCancellationToken cancellationToken)
        {
            listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, $"CFindSource version is {typeof(CFindSource).Assembly.GetName().Version}.  Assembly is {typeof(PACSSource).Assembly} "));
            listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, $"Fo-Dicom version is {typeof(DicomClient).Assembly.GetName().Version}.  Assembly is {typeof(DicomClient).Assembly} "));

            var dicomConfiguration = GetConfiguration();
            var requestSender      = new DicomRequestSender(dicomConfiguration, listener);
            var dateFrom           = Request.Start;
            var dateTo             = Request.End;

            CachingSCP.LocalAet = LocalAETitle;
            CachingSCP.Listener = listener;

            if (PatientIdWhitelistColumnInfo != null && !IgnoreWhiteList)
            {
                GetWhitelist(listener);
            }

            //temp dir
            var cacheDir    = new LoadDirectory(Request.CacheProgress.LoadProgress.LoadMetadata.LocationOfFlatFiles).Cache;
            var cacheLayout = new SMICacheLayout(cacheDir, new SMICachePathResolver(Modality));

            Chunk = new SMIDataChunk(Request)
            {
                FetchDate = dateFrom,
                Modality  = Modality,
                Layout    = cacheLayout
            };

            // Create filepath for the results of the C-Find
            var workingDirectory = cacheLayout.GetLoadCacheDirectory(listener);
            var filename         = $"{dateFrom:yyyyMMddhhmmss}.csv";
            var filepath         = Path.Combine(workingDirectory.FullName, filename);

            var sw     = new StreamWriter(filepath);
            var writer = new CsvWriter(sw, new CsvConfiguration(CultureInfo.CurrentCulture));

            WriteHeaders(writer);

            DicomClient client = new DicomClient(dicomConfiguration.RemoteAetUri.Host, dicomConfiguration.RemoteAetUri.Port, false, dicomConfiguration.LocalAetTitle, dicomConfiguration.RemoteAetTitle);

            try
            {
                // Find a list of studies
                #region Query

                listener.OnNotify(this,
                                  new NotifyEventArgs(ProgressEventType.Information,
                                                      "Requesting Studies from " + dateFrom + " to " + dateTo));
                int responses = 0;

                var request = CreateStudyRequestByDateRangeForModality(dateFrom, dateTo, Modality);
                request.OnResponseReceived += (req, response) =>
                {
                    if (Filter(Whitelist, response))
                    {
                        Interlocked.Increment(ref responses);
                        WriteResult(writer, response);
                    }
                };
                requestSender.ThrottleRequest(request, client, cancellationToken.AbortToken);
                listener.OnNotify(this,
                                  new NotifyEventArgs(ProgressEventType.Debug,
                                                      "Total filtered studies for " + dateFrom + " to " + dateTo + " is " + responses));
                #endregion
            }
            finally
            {
                writer.Dispose();
            }


            return(Chunk);
        }
 public MultiDayCacheFetchRequestProvider(ICacheFetchRequest initialRequest, DateTime endDateInclusive)
 {
     Current           = null;
     _initialRequest   = initialRequest;
     _endDateInclusive = endDateInclusive;
 }