public async Task <IActionResult> Run(int iterations, string type) { var running = await _jobService.AlgorithmIsRunning(); if (running) { return(StatusCode(409, "Algorithm is already running")); } var ratingJob = new RatingJob { JobId = 0, StartTime = DateTime.Now, }; int jobId; switch (type) { case "singles": ratingJob.Type = "Algorithm.Singles"; await _ratingJobRepository.Insert(ratingJob); var singlesInstance = (Algorithm)_serviceProvider.GetService(typeof(Algorithm)); jobId = int.Parse(BackgroundJob.Enqueue(() => singlesInstance.UpdateRating(iterations, false, ratingJob.Id))); break; case "doubles": ratingJob.Type = "Algorithm.Doubles"; await _ratingJobRepository.Insert(ratingJob); var doublesInstance = (AlgorithmDoubles)_serviceProvider.GetService(typeof(AlgorithmDoubles)); jobId = int.Parse(BackgroundJob.Enqueue(() => doublesInstance.UpdateRating(iterations, null, ratingJob.Id))); break; default: return(StatusCode(400, "Type must be singles or doubles")); } ratingJob.JobId = jobId; await _ratingJobRepository.Update(ratingJob); return(StatusCode(200, "Algorithm started")); }
public async Task UpdateRating(int count, bool asAlternate, int jobId) { // resolve any events await _playerService.ResolvePlayerEvents(); // await _resultService.ResolveResultEvents(); _ratingJobId = jobId; var conn = new SqlConnection(_config.ConnectionStrings.DefaultConnection); SqlTransaction transaction = null; RatingRule rule = RatingRule.GetDefault("singles", _config.ConnectionStrings.DefaultConnection); try { _logger.LogInformation("Started Singles Algorithm - {0} iterations", count); var resultThreshold = DateTime.UtcNow.AddMonths(-1 * int.Parse(_config.OldestResultInMonths)); _logger.LogInformation("Retrieving Players..."); await LogStatus("Loading players..."); var players = (await _playerService.GetPlayersWithResults("singles", resultThreshold)).ToDictionary(item => item.Id); _logger.LogInformation("Retrieving Results..."); await LogStatus("Loading results..."); var playerResults = await _resultService.GetPlayerResultsFromYear("singles", resultThreshold); _logger.LogInformation("Running calculations..."); await DoCalculation(count, players, rule, playerResults); _logger.LogInformation("Calculating Competitiveness..."); await LogStatus("Calculating competitiveness..."); foreach (var row in players.Values) { if (playerResults == null || playerResults.Count <= 0) { continue; } var player = row; var results = GetRatingResults(player, players, playerResults[player.Id], rule); var comp = CalculateCompetitiveness(results); row.Stats.CompetitiveMatchPct = comp.Item1; row.Stats.RoutineMatchPct = comp.Item2; row.Stats.DecisiveMatchPct = comp.Item3; } _logger.LogInformation("Correcting players..."); await LogStatus("Correcting players..."); DoPostProcessing(playerResults, players.Values.ToList(), rule); _logger.LogInformation("Saving Sub Ratings"); await LogStatus("Saving Sub Ratings..."); foreach (var player in players.Values) { // update sub rating if (player.Stats.SubRating != null) { await _subRatingRepository.AddOrUpdateSubRating(player.Stats.SubRating); } } _logger.LogInformation("Saving Ratings"); await LogStatus("Saving Ratings..."); conn.Open(); transaction = conn.BeginTransaction(); foreach (var player in players.Values) { conn.Execute(@"update playerrating set finalrating = @FinalRating, actualrating = @ActualRating, ratingreliability = @RatingReliability, " + "competitiveMatchPct = @CompetitiveMatchPct, routineMatchPct = @RoutineMatchPct, decisiveMatchPct = @DecisiveMatchPct, " + "inactiveRating = NULL, activeSinglesResults = @ActiveSinglesResults, playergender = @Gender where playerId = @Id", new { Id = player.Id, CompetitiveMatchPct = player.Stats.CompetitiveMatchPct, RoutineMatchPct = player.Stats.RoutineMatchPct, DecisiveMatchPct = player.Stats.DecisiveMatchPct, RatingReliability = player.Stats.RatingReliability, ActualRating = player.Stats.ActualRating, FinalRating = player.Stats.FinalRating, Gender = player.Gender, ActiveSinglesResults = player.Stats.ActiveSinglesResults }, transaction: transaction); } transaction.Commit(); // clean up the players players = null; GC.Collect(); UpdateDisconnectedPools(rule, playerResults); await LogStatus("Completed"); _logger.LogInformation("Algorithm Completed Successfully"); } catch (Exception e) { try { transaction?.Rollback(); } catch (Exception e2) { LogException(e2); } LogException(e); _logger.LogError("Algorithm Failed"); await LogStatus("Failed"); } finally { transaction?.Dispose(); conn.Close(); // close the job var job = await _ratingJobRepository.GetById(_ratingJobId); job.EndTime = DateTime.Now; await _ratingJobRepository.Update(job); } }
public async Task UpdateRating(int count, RatingRule rule, int jobId) { // resolve any events await _playerService.ResolvePlayerEvents(); // await _resultService.ResolveResultEvents(); _ratingJobId = jobId; try { // always update the rule _ratingRule = rule ?? RatingRule.GetDefault("doubles", _config.ConnectionStrings.DefaultConnection); await LogStatus("Loading Players..."); _logger.LogInformation("Retrieving Players..."); await LogStatus("Loading players..."); var resultThreshold = DateTime.UtcNow.AddMonths(-1 * int.Parse(_config.OldestResultInMonths)); var players = (await _playerService.GetPlayersWithResults("doubles", resultThreshold)).ToDictionary(item => item.Id); // all doubles results in the last year _logger.LogInformation("Retrieving Results..."); await LogStatus("Loading results..."); var results = await _resultService.GetPlayerResultsFromYear("doubles", resultThreshold); _logger.LogInformation("Running calculations..."); for (var i = 0; i < count; i++) { await LogStatus($"Running calculations - Iteration {i + 1}"); DoCalc(players, i + 1, results); } _logger.LogInformation("Calculating Competitiveness..."); await LogStatus("Calculating competitiveness..."); foreach (var player in players) { var ratingResults = LoadRatingResults(results[player.Value.Id]); player.Value.Stats.CompetitiveMatchPctDoubles = CalculateCompetitiveness(ratingResults); } _logger.LogInformation("Correcting players..."); await LogStatus("Correcting players..."); NormalizeRatingsII(players.Values.ToList(), results); _logger.LogInformation("Saving Ratings"); await LogStatus("Saving Ratings..."); using (var connection = new SqlConnection(_config.ConnectionStrings.DefaultConnection)) { connection.Open(); using (var transaction = connection.BeginTransaction()) { const string updateQuery = "Update PlayerRating Set FinalDoublesRating = @FinalDoublesRating, DoublesRating = @DoublesRating, DoublesReliability = @DoublesReliability," + " CompetitiveMatchPctDoubles = @CompetitiveMatchPctDoubles, ActiveDoublesResults = @ActiveDoublesResults, DoublesBenchmarkRating = @DoublesBenchmarkRating" + " PlayerGender = @Gender Where playerid = @Id"; foreach (var player in players) { connection.Execute(updateQuery, new { DoublesRating = player.Value.Stats.DoublesRating, DoublesReliability = player.Value.Stats.DoublesReliability, FinalDoublesRating = player.Value.Stats.FinalDoublesRating, CompetitiveMatchPctDoubles = player.Value.Stats.CompetitiveMatchPctDoubles, DoublesBenchmarkRating = player.Value.Stats.DoublesBenchmarkRating, Id = player.Value.Id, Gender = player.Value.Gender, ActiveDoublesResults = player.Value.Stats.ActiveDoublesResults }, transaction: transaction); } transaction.Commit(); } } // clean up players players = null; GC.Collect(); await LogStatus("Checking for disconnected pools..."); UpdateDisconnectedPools(results); await LogStatus("Completed"); _logger.LogInformation("Algorithm Completed Successfully"); } catch (Exception e) { LogException(e); _logger.LogInformation("Algorithm Failed"); await LogStatus("Failed"); } finally { // close the job var job = await _ratingJobRepository.GetById(_ratingJobId); job.EndTime = DateTime.Now; await _ratingJobRepository.Update(job); } }