Пример #1
0
        /// <summary>
        /// Starts up service and begins listening with the <see cref="Consumer"/>
        /// </summary>
        public override void Start()
        {
            FansiImplementations.Load();

            IRDMPPlatformRepositoryServiceLocator repositoryLocator = Globals.RDMPOptions.GetRepositoryProvider();

            var startup = new Startup(new EnvironmentInfo("netcoreapp2.2"), repositoryLocator);

            var toMemory = new ToMemoryCheckNotifier();

            startup.DoStartup(toMemory);

            foreach (CheckEventArgs args in toMemory.Messages.Where(m => m.Result == CheckResult.Fail))
            {
                Logger.Log(LogLevel.Warn, args.Ex, args.Message);
            }

            _fileMessageProducer = RabbitMqAdapter.SetupProducer(Globals.CohortExtractorOptions.ExtractFilesProducerOptions, isBatch: true);
            IProducerModel fileMessageInfoProducer = RabbitMqAdapter.SetupProducer(Globals.CohortExtractorOptions.ExtractFilesInfoProducerOptions, isBatch: false);

            InitializeExtractionSources(repositoryLocator);

            Consumer = new ExtractionRequestQueueConsumer(Globals.CohortExtractorOptions, _fulfiller, _auditor, _pathResolver, _fileMessageProducer, fileMessageInfoProducer);

            RabbitMqAdapter.StartConsumer(_consumerOptions, Consumer, isSolo: false);
        }
Пример #2
0
        public MicroserviceTester(RabbitOptions rabbitOptions, params ConsumerOptions[] peopleYouWantToSendMessagesTo)
        {
            CleanUpAfterTest = true;

            _adapter = new RabbitMqAdapter(rabbitOptions.CreateConnectionFactory(), "TestHost");

            Factory = new ConnectionFactory
            {
                HostName    = rabbitOptions.RabbitMqHostName,
                Port        = rabbitOptions.RabbitMqHostPort,
                VirtualHost = rabbitOptions.RabbitMqVirtualHost,
                UserName    = rabbitOptions.RabbitMqUserName,
                Password    = rabbitOptions.RabbitMqPassword
            };

            using (var con = Factory.CreateConnection())
                using (var model = con.CreateModel())
                {
                    //get rid of old exchanges
                    model.ExchangeDelete(rabbitOptions.RabbitMqControlExchangeName);
                    //create a new one
                    model.ExchangeDeclare(rabbitOptions.RabbitMqControlExchangeName, ExchangeType.Topic, true);

                    //setup a sender chanel for each of the consumers you want to test sending messages to
                    foreach (ConsumerOptions consumer in peopleYouWantToSendMessagesTo)
                    {
                        if (!consumer.QueueName.Contains("TEST."))
                        {
                            consumer.QueueName = consumer.QueueName.Insert(0, "TEST.");
                        }

                        var exchangeName = consumer.QueueName.Replace("Queue", "Exchange");

                        //terminate any old queues / exchanges
                        model.ExchangeDelete(exchangeName);
                        model.QueueDelete(consumer.QueueName);
                        _declaredExchanges.Add(exchangeName);

                        //Create a binding between the exchange and the queue
                        model.ExchangeDeclare(exchangeName, ExchangeType.Direct, true); //durable seems to be needed because RabbitMQAdapter wants it?
                        model.QueueDeclare(consumer.QueueName, true, false, false);     //shared with other users
                        model.QueueBind(consumer.QueueName, exchangeName, "");
                        _declaredQueues.Add(consumer.QueueName);

                        //Create a producer which can send to the
                        var producerOptions = new ProducerOptions
                        {
                            ExchangeName = exchangeName
                        };

                        _sendToConsumers.Add(consumer, _adapter.SetupProducer(producerOptions, true));
                    }
                }
        }
Пример #3
0
        public IdentifierMapperHost(GlobalOptions options, ISwapIdentifiers swapper = null)
            : base(options)
        {
            _consumerOptions = options.IdentifierMapperOptions;

            FansiImplementations.Load();

            if (swapper == null)
            {
                Logger.Info("Not passed a swapper, creating one of type " + options.IdentifierMapperOptions.SwapperType);
                _swapper = ObjectFactory.CreateInstance <ISwapIdentifiers>(options.IdentifierMapperOptions.SwapperType, typeof(ISwapIdentifiers).Assembly);
            }
            else
            {
                _swapper = swapper;
            }

            // If we want to use a Redis server to cache answers then wrap the mapper in a Redis caching swapper
            if (!string.IsNullOrWhiteSpace(options.IdentifierMapperOptions.RedisConnectionString))
            {
                try
                {
                    _swapper = new RedisSwapper(options.IdentifierMapperOptions.RedisConnectionString, _swapper);
                }
                catch (RedisConnectionException e)
                {
                    // NOTE(rkm 2020-03-30) Log & throw! I hate this, but if we don't log here using NLog, then the exception will bubble-up
                    //                      and only be printed to STDERR instead of to the log file and may be lost
                    Logger.Error(e, "Could not connect to Redis");
                    throw;
                }
            }

            _swapper.Setup(_consumerOptions);
            Logger.Info($"Swapper of type {_swapper.GetType()} created");

            // Batching now handled implicitly as backlog demands
            _producerModel = RabbitMqAdapter.SetupProducer(options.IdentifierMapperOptions.AnonImagesProducerOptions, isBatch: true);

            Consumer = new IdentifierMapperQueueConsumer(_producerModel, _swapper)
            {
                AllowRegexMatching = options.IdentifierMapperOptions.AllowRegexMatching
            };

            // Add our event handler for control messages
            AddControlHandler(new IdentifierMapperControlMessageHandler(_swapper));
        }
Пример #4
0
        public DicomTagReaderHost(GlobalOptions options)
            : base(options)
        {
            if (!Directory.Exists(options.FileSystemOptions.FileSystemRoot))
            {
                throw new ArgumentException("Cannot find the FileSystemRoot specified in the given MicroservicesOptions (" + options.FileSystemOptions.FileSystemRoot + ")");
            }

            Logger.Debug("Creating DicomTagReaderHost with FileSystemRoot: " + options.FileSystemOptions.FileSystemRoot);
            Logger.Debug("NackIfAnyFileErrors option set to " + options.DicomTagReaderOptions.NackIfAnyFileErrors);

            IProducerModel seriesProducerModel;
            IProducerModel imageProducerModel;

            try
            {
                Logger.Debug("Creating seriesProducerModel with ExchangeName: " + options.DicomTagReaderOptions.SeriesProducerOptions.ExchangeName);
                seriesProducerModel = RabbitMqAdapter.SetupProducer(options.DicomTagReaderOptions.SeriesProducerOptions, true);

                Logger.Debug("Creating imageProducerModel with ExchangeName: " + options.DicomTagReaderOptions.ImageProducerOptions.ExchangeName);
                imageProducerModel = RabbitMqAdapter.SetupProducer(options.DicomTagReaderOptions.ImageProducerOptions, true);
            }
            catch (Exception e)
            {
                throw new ApplicationException("Couldn't create series producer model on startup", e);
            }

            Logger.Debug("Creating AccessionDirectoryMessageConsumer");

            switch (options.DicomTagReaderOptions.TagProcessorMode)
            {
            case TagProcessorMode.Serial:
                _tagReader = new SerialTagReader(options.DicomTagReaderOptions, options.FileSystemOptions, seriesProducerModel, imageProducerModel, new FileSystem());
                break;

            case TagProcessorMode.Parallel:
                _tagReader = new ParallelTagReader(options.DicomTagReaderOptions, options.FileSystemOptions, seriesProducerModel, imageProducerModel, new FileSystem());
                break;

            default:
                throw new ArgumentException($"No case for mode {options.DicomTagReaderOptions.TagProcessorMode}");
            }

            // Setup our consumer
            AccessionDirectoryMessageConsumer = new DicomTagReaderConsumer(_tagReader, options);
        }
Пример #5
0
        public DicomReprocessorHost(GlobalOptions options, DicomReprocessorCliOptions cliOptions)
            : base(options)
        {
            string key = cliOptions.ReprocessingRoutingKey;

            if (string.IsNullOrWhiteSpace(key))
            {
                throw new ArgumentException("ReprocessingRoutingKey");
            }

            // Set the initial sleep time
            Globals.DicomReprocessorOptions.SleepTime = TimeSpan.FromMilliseconds(cliOptions.SleepTimeMs);

            IProducerModel reprocessingProducerModel = RabbitMqAdapter.SetupProducer(options.DicomReprocessorOptions.ReprocessingProducerOptions, true);

            Logger.Info("Documents will be reprocessed to " +
                        options.DicomReprocessorOptions.ReprocessingProducerOptions.ExchangeName + " on vhost " +
                        options.RabbitOptions.RabbitMqVirtualHost + " with routing key \"" + key + "\"");

            if (!string.IsNullOrWhiteSpace(cliOptions.QueryFile))
            {
                _queryString = File.ReadAllText(cliOptions.QueryFile);
            }

            //TODO Make this into a CreateInstance<> call
            switch (options.DicomReprocessorOptions.ProcessingMode)
            {
            case ProcessingMode.TagPromotion:
                _processor = new TagPromotionProcessor(options.DicomReprocessorOptions, reprocessingProducerModel, key);
                break;

            case ProcessingMode.ImageReprocessing:
                _processor = new DicomFileProcessor(options.DicomReprocessorOptions, reprocessingProducerModel, key);
                break;

            default:
                throw new ArgumentException("ProcessingMode " + options.DicomReprocessorOptions.ProcessingMode + " not supported");
            }

            _mongoReader = new MongoDbReader(options.MongoDatabases.DicomStoreOptions, cliOptions, HostProcessName + "-" + HostProcessID);

            AddControlHandler(new DicomReprocessorControlMessageHandler(Globals.DicomReprocessorOptions));
        }
Пример #6
0
        public FileCopierHost(
            [NotNull] GlobalOptions options,
            [CanBeNull] IFileSystem fileSystem = null
            )
            : base(
                options
                )
        {
            Logger.Debug("Creating FileCopierHost with FileSystemRoot: " + Globals.FileSystemOptions.FileSystemRoot);

            IProducerModel copyStatusProducerModel = RabbitMqAdapter.SetupProducer(Globals.FileCopierOptions.CopyStatusProducerOptions, isBatch: false);

            var fileCopier = new ExtractionFileCopier(
                Globals.FileCopierOptions,
                copyStatusProducerModel,
                Globals.FileSystemOptions.FileSystemRoot,
                Globals.FileSystemOptions.ExtractRoot,
                fileSystem
                );

            _consumer = new FileCopyQueueConsumer(fileCopier);
        }
Пример #7
0
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="cliOptions">Common microservices options.  Must contain details for an message exchange labelled as "accessionDirectories"</param>
        /// <param name="globals">Configuration settings for the program</param>
        public DicomDirectoryProcessorHost(GlobalOptions globals, DicomDirectoryProcessorCliOptions cliOptions)
            : base(globals)
        {
            _cliOptions = cliOptions;

            if (!cliOptions.DirectoryFormat.ToLower().Equals("list"))
            {
                // TODO(rkm 2020-02-12) I think we want to check this regardless of the mode
                // (bp 2020-02-13) By not doing this check on list means that the list of paths is not required to be in PACS and can be imported from anywhere
                if (!Directory.Exists(globals.FileSystemOptions.FileSystemRoot))
                {
                    throw new ArgumentException("Cannot find the FileSystemRoot specified in the given MicroservicesOptions (" + globals.FileSystemOptions.FileSystemRoot + ")");
                }

                if (!cliOptions.ToProcessDir.Exists)
                {
                    throw new ArgumentException("Could not find directory " + cliOptions.ToProcessDir.FullName);
                }

                if (!cliOptions.ToProcessDir.FullName.StartsWith(globals.FileSystemOptions.FileSystemRoot, true, CultureInfo.CurrentCulture))
                {
                    throw new ArgumentException("Directory parameter (" + cliOptions.ToProcessDir.FullName + ") must be below the FileSystemRoot (" + globals.FileSystemOptions.FileSystemRoot + ")");
                }
            }
            else
            {
                if (!File.Exists(cliOptions.ToProcessDir.FullName))
                {
                    throw new ArgumentException("Could not find accession directory list file (" + cliOptions.ToProcessDir.FullName + ")");
                }

                if (!Path.GetExtension(cliOptions.ToProcessDir.FullName).Equals(".csv"))
                {
                    throw new ArgumentException("When in 'list' mode, path to accession directory file of format .csv expected (" + cliOptions.ToProcessDir.FullName + ")");
                }
            }

            if (cliOptions.DirectoryFormat.ToLower().Equals("pacs"))
            {
                Logger.Info("Creating PACS directory finder");

                _ddf = new PacsDirectoryFinder(globals.FileSystemOptions.FileSystemRoot,
                                               globals.FileSystemOptions.DicomSearchPattern, RabbitMqAdapter.SetupProducer(globals.ProcessDirectoryOptions.AccessionDirectoryProducerOptions, isBatch: false));
            }
            else if (cliOptions.DirectoryFormat.ToLower().Equals("list"))
            {
                Logger.Info("Creating accession directory lister");

                _ddf = new AccessionDirectoryLister(globals.FileSystemOptions.FileSystemRoot,
                                                    globals.FileSystemOptions.DicomSearchPattern, RabbitMqAdapter.SetupProducer(globals.ProcessDirectoryOptions.AccessionDirectoryProducerOptions, isBatch: false));
            }
            else if (cliOptions.DirectoryFormat.ToLower().Equals("default"))
            {
                Logger.Info("Creating basic directory finder");

                _ddf = new BasicDicomDirectoryFinder(globals.FileSystemOptions.FileSystemRoot,
                                                     globals.FileSystemOptions.DicomSearchPattern, RabbitMqAdapter.SetupProducer(globals.ProcessDirectoryOptions.AccessionDirectoryProducerOptions, isBatch: false));
            }
            else if (cliOptions.DirectoryFormat.ToLower().Equals("zips"))
            {
                Logger.Info("Creating zip directory finder");

                _ddf = new ZipDicomDirectoryFinder(globals.FileSystemOptions.FileSystemRoot,
                                                   globals.FileSystemOptions.DicomSearchPattern, RabbitMqAdapter.SetupProducer(globals.ProcessDirectoryOptions.AccessionDirectoryProducerOptions, isBatch: false));
            }
            else
            {
                throw new ArgumentException("Could not match directory format " + cliOptions.DirectoryFormat + " to an directory scan implementation");
            }
        }
Пример #8
0
 public TriggerUpdatesHost(GlobalOptions options, ITriggerUpdatesSource source, IRabbitMqAdapter rabbitMqAdapter = null)
     : base(options, rabbitMqAdapter)
 {
     this._source = source;
     _producer    = RabbitMqAdapter.SetupProducer(options.TriggerUpdatesOptions, isBatch: false);
 }