Beispiel #1
0
        public async Task Empty_slots_in_channels_from_db_results_in_new_jobs_with_2_possible_jobs_per_channel_but_queue_4_only_one_large_job()
        {
            var channelAssignmentDefinition = new ChannelAssignmentDefinition
            {
                Channel1 = "1,2,3",
                Channel2 = "1,2,3,4,5,6,7",
                Channel3 = "1,2,3,4,5,6,7,8,9",
                Channel4 = "6,7,8,9,1,2,3,4,5"
            };
            var db = new Mock <IPrimaerdatenAuftragAccess>();

            // 0 job is running on channel 1, 1 job on channel 2 and zero on 3 and 4
            db.Setup(d => d.GetCurrentWorkload(AufbereitungsArtEnum.Download))
            .Returns(Task.FromResult(new Dictionary <int, int> {
                { 1, 0 }, { 2, 1 }, { 3, 0 }, { 4, 0 }
            }));
            // return primaerdatenAuftragId for next possible job
            db.Setup(d => d.GetNextJobsForChannel(AufbereitungsArtEnum.Download, new[] { 1, 2, 3 }, It.IsAny <int>(), It.IsAny <int[]>()))
            .Returns(Task.FromResult(new List <int> {
                100, 110
            }));
            db.Setup(d => d.GetNextJobsForChannel(AufbereitungsArtEnum.Download, new[] { 1, 2, 3, 4, 5, 6, 7 }, It.IsAny <int>(), It.IsAny <int[]>()))
            .Returns(Task.FromResult(new List <int> {
                200, 210
            }));
            db.Setup(d => d.GetNextJobsForChannel(AufbereitungsArtEnum.Download, new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, It.IsAny <int>(),
                                                  It.IsAny <int[]>())).Returns(Task.FromResult(new List <int> {
                300, 310
            }));
            // DB returns only 1 job for categories 6,7,8,9, so when requesting two jobs a job from 1,2,3,4,5 can be used.
            db.Setup(d => d.GetNextJobsForChannel(AufbereitungsArtEnum.Download, new[] { 6, 7, 8, 9 }, It.IsAny <int>(), It.IsAny <int[]>()))
            .Returns(Task.FromResult(new List <int> {
                400
            }));
            db.Setup(d => d.GetNextJobsForChannel(AufbereitungsArtEnum.Download, new[] { 1, 2, 3, 4, 5 }, It.IsAny <int>(), It.IsAny <int[]>()))
            .Returns(Task.FromResult(new List <int> {
                500, 510
            }));
            // Prefetch count 8 results in two possible jobs per channel
            var engine = new PackagePriorizationEngine(db.Object, channelAssignmentDefinition,
                                                       new RepositoryQueuesPrefetchCount {
                SyncQueuePrefetchCount = 6, DownloadQueuePrefetchCount = 8
            });

            var newJobs = await engine.GetNextJobsForExecution(AufbereitungsArtEnum.Download);

            newJobs.Count.Should().Be(4);
            newJobs[1].Should().BeEquivalentTo(new[] { 100, 110 });
            newJobs[2].Should().BeEquivalentTo(new[] { 200 });
            newJobs[3].Should().BeEquivalentTo(new[] { 300, 310 });
            newJobs[4].Should().BeEquivalentTo(new[] { 400, 500 });
        }
Beispiel #2
0
        public void A_ChannelAssignementDefinition_is_correctly_split_in_ranges_2()
        {
            channelAssignmentDefinition = new ChannelAssignmentDefinition
            {
                Channel1 = "3,2,1",
                Channel2 = "1,2,3,4,5,6,7",
                Channel3 = "1,2,3,4,5,6,7,8,9",
                Channel4 = "6,7,8,9,4,5,1,2,3"
            };

            var engine = new PackagePriorizationEngine(null, channelAssignmentDefinition,
                                                       new RepositoryQueuesPrefetchCount {
                SyncQueuePrefetchCount = 6, DownloadQueuePrefetchCount = 4
            });

            engine.KategorieRangesPerChannel[1].Should().HaveCount(3);
            engine.KategorieRangesPerChannel[2].Should().HaveCount(1);
            engine.KategorieRangesPerChannel[3].Should().HaveCount(1);
            engine.KategorieRangesPerChannel[4].Should().HaveCount(3);

            engine.KategorieRangesPerChannel[1].Should()
            .BeEquivalentTo(new List <List <int> > {
                new List <int> {
                    3
                }, new List <int> {
                    2
                }, new List <int> {
                    1
                }
            });
            engine.KategorieRangesPerChannel[2].Should().BeEquivalentTo(new List <List <int> > {
                new List <int> {
                    1, 2, 3, 4, 5, 6, 7
                }
            });
            engine.KategorieRangesPerChannel[3].Should().BeEquivalentTo(new List <List <int> > {
                new List <int> {
                    1, 2, 3, 4, 5, 6, 7, 8, 9
                }
            });
            engine.KategorieRangesPerChannel[4].Should().BeEquivalentTo(new List <List <int> >
            {
                new List <int> {
                    6, 7, 8, 9
                }, new List <int> {
                    4, 5
                }, new List <int> {
                    1, 2, 3
                }
            });
        }
Beispiel #3
0
        public async Task Empty_slots_in_all_channels_from_db_results_in_new_jobs()
        {
            var channelAssignmentDefinition = new ChannelAssignmentDefinition
            {
                Channel1 = "1,2,3",
                Channel2 = "1,2,3,4,5,6,7",
                Channel3 = "1,2,3,4,5,6,7,8,9",
                Channel4 = "6,7,8,9,1,2,3,4,5"
            };
            var db = new Mock <IPrimaerdatenAuftragAccess>();

            // 0 job is running on channels
            db.Setup(d => d.GetCurrentWorkload(AufbereitungsArtEnum.Download))
            .Returns(Task.FromResult(new Dictionary <int, int> {
                { 1, 0 }, { 2, 0 }, { 3, 0 }, { 4, 0 }
            }));
            // return primaerdatenAuftragId for next possible job
            db.Setup(d => d.GetNextJobsForChannel(AufbereitungsArtEnum.Download, new[] { 1, 2, 3 }, It.IsAny <int>(), It.IsAny <int[]>()))
            .Returns(Task.FromResult(new List <int> {
                100
            }));
            db.Setup(d => d.GetNextJobsForChannel(AufbereitungsArtEnum.Download, new[] { 1, 2, 3, 4, 5, 6, 7 }, It.IsAny <int>(), It.IsAny <int[]>()))
            .Returns(Task.FromResult(new List <int> {
                200
            }));
            db.Setup(d => d.GetNextJobsForChannel(AufbereitungsArtEnum.Download, new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, It.IsAny <int>(),
                                                  It.IsAny <int[]>())).Returns(Task.FromResult(new List <int> {
                300
            }));
            db.Setup(d => d.GetNextJobsForChannel(AufbereitungsArtEnum.Download, new[] { 6, 7, 8, 9 }, It.IsAny <int>(), It.IsAny <int[]>()))
            .Returns(Task.FromResult(new List <int> {
                400
            }));
            db.Setup(d => d.GetNextJobsForChannel(AufbereitungsArtEnum.Download, new[] { 1, 2, 3, 4, 5 }, It.IsAny <int>(), It.IsAny <int[]>()))
            .Returns(Task.FromResult(new List <int> {
                500
            }));
            var engine = new PackagePriorizationEngine(db.Object, channelAssignmentDefinition,
                                                       new RepositoryQueuesPrefetchCount {
                SyncQueuePrefetchCount = 6, DownloadQueuePrefetchCount = 4
            });

            var newJobs = await engine.GetNextJobsForExecution(AufbereitungsArtEnum.Download);

            newJobs.Count.Should().Be(4);
            newJobs[1].Should().BeEquivalentTo(new[] { 100 });
            newJobs[2].Should().BeEquivalentTo(new[] { 200 });
            newJobs[3].Should().BeEquivalentTo(new[] { 300 });
            newJobs[4].Should().BeEquivalentTo(new[] { 400 });
        }
        /// <summary>
        ///     Die Priorisierungsengine liefert den nächsten Job für die verschiedenen Kanäle.
        ///     Dazu wird geschaut wieviele Aufträge aktuell im Repository Service am laufen sind und in welchen Kanälen.
        ///
        ///     Wenn es in einem Kanal Platz hat, wird der nächste pendente Auftrag aus der Datenbank abgerufen.
        ///
        ///     Es wird mit 4 Kanälen gerechnet, d.h. alle Aufträge werden anhand ihrer Grösse in eine Priorisierungskategorie
        ///     eingeteilt.
        ///     Die Auftäge werden dann anhand der Priorisierungskategorie einem der 4 Kanäle zugeordnet.
        /// </summary>
        /// <param name="primaerdatenDb">Der Datenbankzugriff auf die Primärdaten Jobs.</param>
        /// <param name="channelAssignmentDefinition">
        ///     Die Konfiguration welche Priorisierungskategorien in welchen Kanälen
        ///     zugeordnet werden können
        /// </param>
        /// <param name="prefetchCount">Einstellungen wieviele parallele Jobs die Repository Queue (RabbitMq) verarbeiten kann.</param>
        public PackagePriorizationEngine(IPrimaerdatenAuftragAccess primaerdatenDb, ChannelAssignmentDefinition channelAssignmentDefinition,
                                         RepositoryQueuesPrefetchCount prefetchCount)
        {
            this.primaerdatenDb = primaerdatenDb;

            // Fülle in einen Dictionary wieviele Jobs pro Kanal verfügbar sind.
            MaxJobCountPerChannelForSync     = GetMaxJobCountPerChannel(prefetchCount.SyncQueuePrefetchCount);
            MaxJobCountPerChannelForDownload = GetMaxJobCountPerChannel(prefetchCount.DownloadQueuePrefetchCount);

            // Definieren die KategorieRanges pro Kanal
            KategorieRangesPerChannel = new Dictionary <int, List <List <int> > >
            {
                { 1, SplitKategorienInRanges(channelAssignmentDefinition.GetPrioritiesForChannel(1)) },
                { 2, SplitKategorienInRanges(channelAssignmentDefinition.GetPrioritiesForChannel(2)) },
                { 3, SplitKategorienInRanges(channelAssignmentDefinition.GetPrioritiesForChannel(3)) },
                { 4, SplitKategorienInRanges(channelAssignmentDefinition.GetPrioritiesForChannel(4)) }
            };

            Log.Debug(
                "Initialized Package Priorization Engine with the following settings: Max job count for sync: {MaxJobCountPerChannelForSync}. " +
                "Max job count for download: {MaxJobCountPerChannelForDownload}", MaxJobCountPerChannelForSync, MaxJobCountPerChannelForDownload);
        }