/// <summary> /// Saves the single quote query result or updates it if it already exists. /// </summary> /// <param name="query"><see cref="SingleQuoteQuery"/> to upsert data for.</param> /// <param name="queryResult"><see cref="SingleQuoteQueryResult"/> stock data results to save.</param> /// <remarks> /// Will update the database and then <see cref="SingleQuoteCache"/> if it was successful. /// Error results will be ignored. /// </remarks> public async Task UpsertSingleQuoteData(SingleQuoteQuery query, SingleQuoteQueryResult queryResult) { if (queryResult.HasError) { return; } _logger.LogTrace("Query SymbolId {id} added to cache", query.SymbolId); const int primaryKeyViolationCode = 2627; try { bool successfulSave = await _stockDataRepository.UpsertSingleQuoteData(new UpsertSingleQuoteData(query.SymbolId, queryResult.Data)); _logger.LogTrace("Query SymbolId {id} saved to database", query.SymbolId); if (!successfulSave) { throw new ArgumentException($"query for symbolId {query.SymbolId} was not able to be updated"); } } catch (SqlException ex) when(ex.ErrorCode == primaryKeyViolationCode) { _logger.LogError("Query SymbolId {id} was duplicate insert in database", query.SymbolId); // Ignore the error since it means a race condition where we tried insert twice. // But that's fine since the stock data is unlikely to be different if it's that close in time. // This is more performant than adding locks as this case should be very exceptional. } // Only insert into cache if it successfully saved into database. _singleQuoteCache.Upsert(query.SymbolId, queryResult); }
public async Task GetSingleQuoteData_ShouldGetValueFromCache() { var query = new SingleQuoteQuery(1); var queryResult = new SingleQuoteQueryResult("MSFT", _singleQuoteData); _cache.Upsert(query.SymbolId, queryResult); StockSingleQuoteDataDTO data = await _service.GetSingleQuoteData(query.SymbolId); Assert.Equal(queryResult.Data, data.Data); _stockDataRepository.Verify(s => s.GetSingleQuoteData(It.IsAny <int>()), Times.Never); }