public async Task <Dictionary <int, int[]> > GetNextJobsForExecution(AufbereitungsArtEnum aufbereitungsArt) { Log.Debug("Fetching next jobs for execution from priorization engine."); var newJobsPerChannel = new Dictionary <int, int>(); // Hole die aktuelle Auslastung von der Datenbank // die im Repository Service in der Arbeit sind var workload = await primaerdatenDb.GetCurrentWorkload(aufbereitungsArt); Log.Debug("The current workload is: {workload}", JsonConvert.SerializeObject(workload)); // Schaue ob alle channels gefüllt sind foreach (var channelWorkload in workload) { // Hole die Anzahl der möglichen Jobs in der Queue für die Aufbereitungsart var possibleJobs = GetPossibleJobs(aufbereitungsArt, channelWorkload.Key); // Anzahl der zu startenden neuen Jobs ist mögliche Anzahl minus der aktuellen Auslastung var newJobsToStart = possibleJobs - workload[channelWorkload.Key]; if (newJobsToStart > 0) { newJobsPerChannel.Add(channelWorkload.Key, newJobsToStart); } } // Hole die nächsten Jobs anhand der möglichen neuen Jobs Log.Debug("We are able to fetch pending jobs as follows: {newJobsPerChannel}", JsonConvert.SerializeObject(newJobsPerChannel)); var retVal = await FetchPendingJobsFromDatabase(aufbereitungsArt, newJobsPerChannel); Log.Debug("The following jobs can be started: {retVal}", JsonConvert.SerializeObject(retVal)); return(retVal); }
private int GetPossibleJobs(AufbereitungsArtEnum aufbereitungsArt, int channel) { switch (aufbereitungsArt) { case AufbereitungsArtEnum.Sync: return(MaxJobCountPerChannelForSync[channel]); case AufbereitungsArtEnum.Download: return(MaxJobCountPerChannelForDownload[channel]); default: throw new ArgumentOutOfRangeException(nameof(aufbereitungsArt), aufbereitungsArt, null); } }
public async Task <List <int> > GetNextJobsForChannel(AufbereitungsArtEnum aufbereitungsArt, int[] priorisierungsKategorien, int anzahlJobs, int[] primaerdatenAuftragIdsToExclude) { var retVal = new List <int>(); using (var connection = new SqlConnection(connectionString)) { await connection.OpenAsync(); using (var cmd = connection.CreateCommand()) { cmd.CommandText = $@" SELECT TOP {anzahlJobs} PrimaerdatenAuftragId, VeId FROM PrimaerdatenAuftrag WHERE AufbereitungsArt = @Aufbereitungsart AND Status = @Status AND Abgeschlossen = 0 AND PriorisierungsKategorie IN ({string.Join(",", priorisierungsKategorien)}) "; if (primaerdatenAuftragIdsToExclude.Length > 0) { cmd.CommandText += $@" AND PrimaerdatenAuftragId NOT IN ({string.Join(",", primaerdatenAuftragIdsToExclude)}) "; } cmd.CommandText += " ORDER BY PriorisierungsKategorie, CreatedOn; "; cmd.Parameters.Add(new SqlParameter { ParameterName = "Status", Value = AufbereitungsStatusEnum.Registriert, SqlDbType = SqlDbType.NVarChar }); cmd.Parameters.Add(new SqlParameter { ParameterName = "Aufbereitungsart", Value = aufbereitungsArt.ToString(), SqlDbType = SqlDbType.NVarChar }); using (var reader = await cmd.ExecuteReaderAsync()) { while (await reader.ReadAsync()) { retVal.Add(Convert.ToInt32(reader["PrimaerdatenAuftragId"])); } } } } return(retVal); }
private async Task <Dictionary <int, int[]> > FetchPendingJobsFromDatabase(AufbereitungsArtEnum aufbereitungsArt, Dictionary <int, int> newJobsPerChannel) { var retVal = new Dictionary <int, int[]>(); foreach (var channel in newJobsPerChannel) { var jobIds = await FetchNextJobForChannel(aufbereitungsArt, channel.Key, channel.Value, retVal.SelectMany(r => r.Value).ToArray()); Log.Debug("Found the following jobs for channel {Key}: {jobIds}", channel.Key, string.Join(", ", jobIds)); if (jobIds.Count > 0) { retVal.Add(channel.Key, jobIds.ToArray()); } } return(retVal); }
private async Task <List <int> > FetchNextJobForChannel(AufbereitungsArtEnum aufbereitungsArt, int channel, int anzahlJobs, int[] idsToExclude) { var nextJobs = new List <int>(); // Spezialfall: Im Normalfall sollten die Kategorien fortlaufend nummeriert sein. Aber es gibt den Fall für Kanal 4 // der definiert dass Prioritäten zuerst 6-9 verarbeitet werden sollen, und wenn es dann nichts mehr hat die Prioritäten 1-5 // Daher müssen wir die Kategorien anschauen und prüfen ob es einen "Bruch" gibt. Wenn ja, dann müssen wir ggf. 2 Db Abfragen // machen. var kategorienRanges = KategorieRangesPerChannel[channel]; foreach (var kategorienRange in kategorienRanges) { nextJobs.AddRange(await primaerdatenDb.GetNextJobsForChannel(aufbereitungsArt, kategorienRange.ToArray(), anzahlJobs, idsToExclude)); if (nextJobs.Count >= anzahlJobs) // Liefere die Jobs zurück, aber maximal soviele wie verlangt wurden. { return(nextJobs.GetRange(0, anzahlJobs)); } } return(nextJobs); }
private int?GetPriorisierungskategorie(AufbereitungsArtEnum aufbereitungsArt, long sizeInBytes, object workload) { switch (aufbereitungsArt) { case AufbereitungsArtEnum.Sync: // This is download Debug.Assert(workload is ArchiveRecordAppendPackage, "Workload must be of type ArchiveRecordAppendPackage"); // Vecteur Aufträge sind diejenigen Aufträge, wo die VE bereits im Elastic Index vorhanden ist, aber dort KEINE Primärdaten hat. // Dieser erhalten die Kategorie 2-5. Die anderen Aufträge die Kategorie 6-9 var elasticRecord = ((ArchiveRecordAppendPackage)workload).ElasticRecord; if (elasticRecord != null && !elasticRecord.PrimaryData.Any()) { return(GetPriorisierungskategorie(sizeInBytes)); } return(GetPriorisierungskategorie(sizeInBytes, 5)); case AufbereitungsArtEnum.Download: return(GetPriorisierungskategorie(sizeInBytes)); default: throw new ArgumentOutOfRangeException(nameof(aufbereitungsArt), aufbereitungsArt, null); } }
public PrimaerdatenAuftrag(int primaerdatenAuftragId, AufbereitungsArtEnum aufbereitungsArt, long?groesseInBytes, int?verarbeitungskanal, int?priorisierungsKategorie, AufbereitungsStatusEnum status, AufbereitungsServices service, string packageId, string packageMetadata, int veId, bool abgeschlossen, DateTime?abgeschlossenAm, int?geschaetzteAufbereitungszeit, string errorText, string workload, DateTime createdOn, DateTime?modifiedOn, List <PrimaerdatenAuftragLog> primaerdatenAuftragLogs) { PrimaerdatenAuftragId = primaerdatenAuftragId; AufbereitungsArt = aufbereitungsArt; GroesseInBytes = groesseInBytes; Verarbeitungskanal = verarbeitungskanal; PriorisierungsKategorie = priorisierungsKategorie; Status = status; Service = service; PackageId = packageId; PackageMetadata = packageMetadata; VeId = veId; Abgeschlossen = abgeschlossen; AbgeschlossenAm = abgeschlossenAm; GeschaetzteAufbereitungszeit = geschaetzteAufbereitungszeit; ErrorText = errorText; Workload = workload; CreatedOn = createdOn; ModifiedOn = modifiedOn; PrimaerdatenAuftragLogs = primaerdatenAuftragLogs; }
/// <summary> /// Liefert wieviele Aufträge in welchem Kanal drin stecken. /// Dabei ist zu berücksichtigen, dass der REpository Service am "arbeiten" ist /// solange der Status "PaketTransferiert" nicht erreicht ist. /// </summary> /// <param name="aufbereitungsArt"></param> /// <returns></returns> public async Task <Dictionary <int, int> > GetCurrentWorkload(AufbereitungsArtEnum aufbereitungsArt) { var retVal = new Dictionary <int, int>(); using (var connection = new SqlConnection(connectionString)) { await connection.OpenAsync(); using (var cmd = connection.CreateCommand()) { // with(nolock) is required as the grouping operator places a lock on the table. // This then conflicts with the insert statements that are used on the same table and uses transactions. cmd.CommandText = @" SELECT Verarbeitungskanal, COUNT(primaerdatenAuftragId) AS Anzahl FROM PrimaerdatenAuftrag with(nolock) WHERE Abgeschlossen = 0 AND (Status = @Status1 OR Status = @Status2 OR Status = @Status3) AND AufbereitungsArt = @Aufbereitungsart AND Service = @Service GROUP BY Verarbeitungskanal"; cmd.Parameters.Add(new SqlParameter { ParameterName = "Status1", Value = AufbereitungsStatusEnum.AuftragGestartet, SqlDbType = SqlDbType.NVarChar }); cmd.Parameters.Add(new SqlParameter { ParameterName = "Status2", Value = AufbereitungsStatusEnum.PrimaerdatenExtrahiert, SqlDbType = SqlDbType.NVarChar }); cmd.Parameters.Add(new SqlParameter { ParameterName = "Status3", Value = AufbereitungsStatusEnum.ZipDateiErzeugt, SqlDbType = SqlDbType.NVarChar }); cmd.Parameters.Add(new SqlParameter { ParameterName = "Aufbereitungsart", Value = aufbereitungsArt.ToString(), SqlDbType = SqlDbType.NVarChar }); cmd.Parameters.Add(new SqlParameter { ParameterName = "Service", Value = AufbereitungsServices.AssetService, SqlDbType = SqlDbType.NVarChar }); using (var reader = await cmd.ExecuteReaderAsync()) { while (reader.Read()) { retVal.Add(Convert.ToInt32(reader["Verarbeitungskanal"]), Convert.ToInt32(reader["Anzahl"])); } } // Make sure we get results for all channels if (!retVal.ContainsKey(1)) { retVal.Add(1, 0); } if (!retVal.ContainsKey(2)) { retVal.Add(2, 0); } if (!retVal.ContainsKey(3)) { retVal.Add(3, 0); } if (!retVal.ContainsKey(4)) { retVal.Add(4, 0); } } } return(retVal); }
public async Task <PrimaerdatenAuftragStatusInfo> GetLaufendenAuftrag(int veId, AufbereitungsArtEnum aufbereitungsArt) { PrimaerdatenAuftragStatusInfo retVal = null; using (var connection = new SqlConnection(connectionString)) { await connection.OpenAsync(); using (var cmd = connection.CreateCommand()) { cmd.CommandText = "SELECT primaerdatenAuftragId, status, service, veId, CreatedOn, ModifiedOn, GeschaetzteAufbereitungszeit, AufbereitungsArt " + "FROM PrimaerdatenAuftrag WHERE veId = @veId and abgeschlossen = 0 and aufbereitungsArt = @aufbereitungsArt"; cmd.Parameters.Add(new SqlParameter { ParameterName = "veId", Value = veId, SqlDbType = SqlDbType.Int }); cmd.Parameters.Add(new SqlParameter { ParameterName = "aufbereitungsArt", Value = aufbereitungsArt.ToString(), SqlDbType = SqlDbType.NVarChar }); using (var reader = await cmd.ExecuteReaderAsync()) { if (reader.HasRows) { await reader.ReadAsync(); retVal = PrimaerdatenAuftragStatusInfoFromReader(reader); } } } } return(retVal); }
/// <summary> /// Registers a preparation job in the queue. /// </summary> /// <param name="archiveRecordId">The archive record identifier.</param> public async Task <int> RegisterJobInPreparationQueue(string archiveRecordId, string packageId, AufbereitungsArtEnum aufbereitungsArt, AufbereitungsServices service, List <ElasticArchiveRecordPackage> primaryData, object workload) { var preperationTime = preparationCalculator.EstimatePreparationDuration(primaryData, aufbereitungsZeitSettings.KonvertierungsgeschwindigkeitAudio, aufbereitungsZeitSettings.KonvertierungsgeschwindigkeitVideo).TotalSeconds; var auftrag = new PrimaerdatenAuftrag { VeId = int.Parse(archiveRecordId), AufbereitungsArt = aufbereitungsArt, PackageId = packageId, Service = service, Status = AufbereitungsStatusEnum.Registriert, GroesseInBytes = primaryData.Sum(p => p.SizeInBytes), GeschaetzteAufbereitungszeit = Convert.ToInt32(preperationTime), Workload = JsonConvert.SerializeObject(workload), PackageMetadata = JsonConvert.SerializeObject(primaryData), PriorisierungsKategorie = GetPriorisierungskategorie(aufbereitungsArt, primaryData.Sum(p => p.SizeInBytes), workload) }; var auftragId = await auftragAccess.CreateOrUpdateAuftrag(auftrag); Log.Information("{METHOD} for VE {VEID} with {STATUS}. AuftragId is {auftragId}", nameof(RegisterJobInPreparationQueue), archiveRecordId, auftragId > 0 ? "SUCCEEDED" : "FAILED", auftragId); return(auftragId); }