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 }); }
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 } }); }
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); }