/// <summary> /// Deletes the item from cache /// </summary> /// <param name="id">A string representing the id of the item in the cache to be deleted</param> /// <param name="cacheItemType">A cache item type</param> public override void CacheDeleteItem(string id, CacheItemType cacheItemType) { if (cacheItemType == CacheItemType.All || cacheItemType == CacheItemType.MarketDescription) { try { foreach (var fetchedVariant in _fetchedVariants) { if (fetchedVariant.Key.StartsWith(id)) { _fetchedVariants.TryRemove(id, out _); } } } catch (Exception e) { ExecutionLog.LogWarning($"Error deleting fetchedVariants for {id}", e); } if (_cache.Contains(id)) { CacheLog.LogDebug($"Delete variant market: {id}"); _cache.Remove(id); } } }
/// <summary> /// Asynchronously gets the <see cref="VariantDescriptionCacheItem"/> specified by it's id. If the item is not found in local cache, all items for specified /// language are fetched from the service and stored/merged into the local cache. /// </summary> /// <param name="id">The id of the <see cref="VariantDescriptionCacheItem"/> instance to get</param> /// <param name="cultures">A <see cref="IEnumerable{CultureInfo}"/> specifying the languages which the returned item must contain</param> /// <returns>A <see cref="Task"/> representing the async operation</returns> /// <exception cref="CommunicationException">An error occurred while accessing the remote party</exception> /// <exception cref="DeserializationException">An error occurred while deserializing fetched data</exception> /// <exception cref="FormatException">An error occurred while mapping deserialized entities</exception> private async Task <VariantDescriptionCacheItem> GetVariantDescriptionInternalAsync(string id, IEnumerable <CultureInfo> cultures) { Guard.Argument(cultures, nameof(cultures)).NotNull().NotEmpty(); var cultureList = cultures as List <CultureInfo> ?? cultures.ToList(); VariantDescriptionCacheItem description; if ((description = GetItemFromCache(id)) != null && !LanguageHelper.GetMissingCultures(cultureList, description.FetchedLanguages).Any()) { return(description); } try { await _semaphore.WaitAsync().ConfigureAwait(false); description = GetItemFromCache(id); var missingLanguages = LanguageHelper.GetMissingCultures(cultureList, description?.FetchedLanguages).ToList(); if (missingLanguages.Any()) { // dont call for already fetched languages missingLanguages = LanguageHelper.GetMissingCultures(missingLanguages, _fetchedLanguages).ToList(); } if (!missingLanguages.Any()) { return(description); } var cultureTaskDictionary = missingLanguages.ToDictionary(l => l, l => _dataRouterManager.GetVariantDescriptionsAsync(l)); await Task.WhenAll(cultureTaskDictionary.Values).ConfigureAwait(false); } catch (Exception ex) { var disposedException = ex as ObjectDisposedException; if (disposedException != null) { ExecutionLog.LogWarning($"An error occurred while fetching market descriptions because the object graph is being disposed. Object causing the exception: {disposedException.ObjectName}."); return(null); } throw; } finally { if (!_isDisposed) { _semaphore.Release(); } } return((description = GetItemFromCache(id)) != null && !LanguageHelper.GetMissingCultures(cultureList, description.FetchedLanguages).Any() ? description : null); }
/// <summary> /// Asynchronously loads the list of market descriptions from the Sports API /// </summary> /// <returns>Returns true if the action succeeded</returns> public async Task <bool> LoadMarketDescriptionsAsync() { try { ExecutionLog.LogDebug($"Loading invariant market descriptions for [{string.Join(",", _prefetchLanguages.Select(l => l.TwoLetterISOLanguageName))}] (user request)."); _fetchedLanguages.Clear(); await GetMarketInternalAsync(0, _prefetchLanguages).ConfigureAwait(false); } catch (Exception ex) { ExecutionLog.LogWarning($"An error occurred while fetching market descriptions. The exception:{ex.Message}"); return(false); } return(true); }
/// <summary> /// Merges the provided descriptions with those found in cache /// </summary> /// <param name="culture">A <see cref="CultureInfo"/> specifying the language of the <code>descriptions</code></param> /// <param name="descriptions">A <see cref="IEnumerable{MarketDescriptionDTO}"/> containing market descriptions in specified language</param> private async Task MergeAsync(CultureInfo culture, IEnumerable <MarketDescriptionDTO> descriptions) { Guard.Argument(culture, nameof(culture)).NotNull(); Guard.Argument(descriptions, nameof(descriptions)).NotNull().NotEmpty(); var descriptionList = descriptions as List <MarketDescriptionDTO> ?? descriptions.ToList(); try { await _semaphoreCacheMerge.WaitAsync().ConfigureAwait(false); foreach (var marketDescription in descriptionList) { try { var cachedItem = _cache.GetCacheItem(marketDescription.Id.ToString()); if (cachedItem == null) { cachedItem = new CacheItem(marketDescription.Id.ToString(), MarketDescriptionCacheItem.Build(marketDescription, _mappingValidatorFactory, culture, CacheName)); _cache.Add(cachedItem, _cacheItemPolicy); } else { ((MarketDescriptionCacheItem)cachedItem.Value).Merge(marketDescription, culture); } } catch (Exception e) { if (!(e is InvalidOperationException)) { throw; } ExecutionLog.LogWarning(e, $"Mapping validation for MarketDescriptionCacheItem failed. Id={marketDescription.Id}"); } } _fetchedLanguages.Add(culture); } finally { if (!_isDisposed) { _semaphoreCacheMerge.ReleaseSafe(); } } }
/// <summary> /// Invoked when the <code>_timer</code> ticks in order to periodically fetch market descriptions for configured languages /// </summary> /// <param name="sender">The <see cref="ITimer"/> raising the event</param> /// <param name="e">A <see cref="EventArgs"/> instance containing the event data</param> private async void OnTimerElapsed(object sender, EventArgs e) { if (_isDisposed) { return; } //when the timer first elapses fetch data only for languages which were not yet fetched. On subsequent timer elapses fetch data for all configured languages var languagesToFetch = _prefetchLanguages.Where(language => !_fetchedLanguages.Contains(language) || _hasTimerElapsedOnce).ToList(); if (!languagesToFetch.Any()) { _hasTimerElapsedOnce = true; return; } try { _fetchedLanguages.Clear(); ExecutionLog.LogDebug($"Loading invariant market descriptions for [{string.Join(",", languagesToFetch.Select(l => l.TwoLetterISOLanguageName))}] (timer)."); await GetMarketInternalAsync(0, languagesToFetch).ConfigureAwait(false); } catch (Exception ex) { if (ex is CommunicationException || ex is DeserializationException || ex is FormatException) { var languagesString = string.Join(",", languagesToFetch.Select(l => l.TwoLetterISOLanguageName)); ExecutionLog.LogWarning($"An error occurred while periodically fetching market description of languages {languagesString}", ex); return; } var disposedException = ex as ObjectDisposedException; if (disposedException != null) { ExecutionLog.LogWarning($"An error occurred while periodically fetching market descriptions because the object graph is being disposed. Object causing the exception:{disposedException.ObjectName}"); return; } if (ex is TaskCanceledException) { ExecutionLog.LogWarning("An error occurred while periodically fetching market descriptions because the object graph is being disposed."); return; } ExecutionLog.LogWarning("An error occurred while periodically fetching market description.", ex); } _hasTimerElapsedOnce = true; }
/// <summary> /// Merges the provided descriptions with those found in cache /// </summary> /// <param name="culture">A <see cref="CultureInfo"/> specifying the language of the <code>descriptions</code></param> /// <param name="description">A <see cref="MarketDescriptionDTO"/> containing market description in specified language</param> private async Task MergeAsync(CultureInfo culture, MarketDescriptionDTO description) { Guard.Argument(culture, nameof(culture)).NotNull(); Guard.Argument(description, nameof(description)).NotNull(); if (_isDisposed) { return; } try { await _semaphoreCacheMerge.WaitAsync().ConfigureAwait(false); var cacheId = GetCacheKey(description.Id, description.Variant); var cachedItem = _cache.GetCacheItem(cacheId); if (cachedItem == null) { cachedItem = new CacheItem(cacheId, MarketDescriptionCacheItem.Build(description, _mappingValidatorFactory, culture, CacheName)); _cache.Add(cachedItem, new CacheItemPolicy { SlidingExpiration = OperationManager.VariantMarketDescriptionCacheTimeout }); } else { ((MarketDescriptionCacheItem)cachedItem.Value).Merge(description, culture); } } catch (Exception e) { if (!(e is InvalidOperationException)) { throw; } ExecutionLog.LogWarning(e, "Mapping validation for MarketDescriptionCacheItem failed."); } finally { _semaphoreCacheMerge.ReleaseSafe(); } }
/// <summary> /// Merges the provided descriptions with those found in cache /// </summary> /// <param name="culture">A <see cref="CultureInfo"/> specifying the language of the <code>descriptions</code></param> /// <param name="descriptions">A <see cref="IEnumerable{MarketDescriptionDTO}"/> containing market descriptions in specified language</param> private void Merge(CultureInfo culture, IEnumerable <VariantDescriptionDTO> descriptions) { Guard.Argument(culture, nameof(culture)).NotNull(); Guard.Argument(descriptions, nameof(descriptions)).NotNull().NotEmpty(); var descriptionList = descriptions as List <VariantDescriptionDTO> ?? descriptions.ToList(); try { _semaphoreCacheMerge.Wait(); foreach (var marketDescription in descriptionList) { var cachedItem = _cache.GetCacheItem(marketDescription.Id); if (cachedItem == null) { cachedItem = new CacheItem(marketDescription.Id, VariantDescriptionCacheItem.Build(marketDescription, _mappingValidatorFactory, culture, CacheName)); _cache.Add(cachedItem, new CacheItemPolicy()); } else { ((VariantDescriptionCacheItem)cachedItem.Value).Merge(marketDescription, culture); } } _fetchedLanguages.Add(culture); } catch (Exception e) { if (!(e is InvalidOperationException)) { throw; } ExecutionLog.LogWarning("Mapping validation for VariantDescriptionCacheItem failed.", e); } finally { if (!_isDisposed) { _semaphoreCacheMerge.Release(); } } }
/// <summary> /// Merges the provided descriptions with those found in cache /// </summary> /// <param name="culture">A <see cref="CultureInfo"/> specifying the language of the <code>descriptions</code></param> /// <param name="description">A <see cref="MarketDescriptionDTO"/> containing market description in specified language</param> private void Merge(CultureInfo culture, MarketDescriptionDTO description) { Guard.Argument(culture, nameof(culture)).NotNull(); Guard.Argument(description, nameof(description)).NotNull(); if (_isDisposed) { return; } try { _semaphoreCacheMerge.Wait(); var cachedItem = _cache.GetCacheItem(GetCacheKey(description.Id, description.Variant)); if (cachedItem == null) { cachedItem = new CacheItem(GetCacheKey(description.Id, description.Variant), MarketDescriptionCacheItem.Build(description, _mappingValidatorFactory, culture, CacheName)); _cache.Add(cachedItem, _cacheItemPolicy); } else { ((MarketDescriptionCacheItem)cachedItem.Value).Merge(description, culture); } } catch (Exception e) { if (!(e is InvalidOperationException)) { throw; } ExecutionLog.LogWarning("Mapping validation for MarketDescriptionCacheItem failed.", e); } finally { if (!_isDisposed) { _semaphoreCacheMerge.Release(); } } }
/// <summary> /// Adds the dto item to cache /// </summary> /// <param name="id">The identifier of the object</param> /// <param name="item">The item to be added</param> /// <param name="culture">The culture of the item</param> /// <param name="dtoType">Type of the dto</param> /// <param name="requester">The cache item which invoked request</param> /// <returns><c>true</c> if added, <c>false</c> otherwise</returns> /// <exception cref="ArgumentOutOfRangeException">dtoType - null</exception> protected override bool CacheAddDtoItem(URN id, object item, CultureInfo culture, DtoType dtoType, ISportEventCI requester) { if (_isDisposed) { return(false); } var saved = false; switch (dtoType) { case DtoType.Category: break; case DtoType.Competitor: break; case DtoType.CompetitorProfile: break; case DtoType.SimpleTeamProfile: break; case DtoType.Fixture: break; case DtoType.MarketDescription: var marketDescription = item as MarketDescriptionDTO; if (marketDescription != null) { //WriteLog($"Saving {marketDescription.Id} variant description for lang: [{culture.TwoLetterISOLanguageName}]."); Merge(culture, marketDescription); saved = true; //WriteLog($"Saving {marketDescription.Id} variant description for lang: [{culture.TwoLetterISOLanguageName}] COMPLETED."); } else { LogSavingDtoConflict(id, typeof(MarketDescriptionDTO), item.GetType(), ExecutionLog); } break; case DtoType.MarketDescriptionList: break; case DtoType.MatchSummary: break; case DtoType.MatchTimeline: break; case DtoType.PlayerProfile: break; case DtoType.RaceSummary: break; case DtoType.Sport: break; case DtoType.SportList: break; case DtoType.SportEventStatus: break; case DtoType.SportEventSummary: break; case DtoType.SportEventSummaryList: break; case DtoType.Tournament: break; case DtoType.TournamentInfo: break; case DtoType.TournamentSeasons: break; case DtoType.VariantDescription: break; case DtoType.VariantDescriptionList: break; case DtoType.Lottery: break; case DtoType.LotteryDraw: break; case DtoType.LotteryList: break; case DtoType.BookingStatus: break; case DtoType.SportCategories: break; case DtoType.AvailableSelections: break; case DtoType.TournamentInfoList: break; default: ExecutionLog.LogWarning($"Trying to add unchecked dto type: {dtoType} for id: {id}."); break; } return(saved); }
/// <summary> /// Adds the dto item to cache /// </summary> /// <param name="id">The identifier of the object</param> /// <param name="item">The item</param> /// <param name="culture">The culture</param> /// <param name="dtoType">Type of the dto</param> /// <param name="requester">The cache item which invoked request</param> /// <returns><c>true</c> if added, <c>false</c> otherwise</returns> protected override bool CacheAddDtoItem(URN id, object item, CultureInfo culture, DtoType dtoType, ISportEventCI requester) { if (_isDisposed) { return(false); } var saved = false; switch (dtoType) { case DtoType.MatchSummary: if (SaveCompetitorsFromSportEvent(item, culture)) { saved = true; } else { LogSavingDtoConflict(id, typeof(MatchDTO), item.GetType()); } break; case DtoType.RaceSummary: if (SaveCompetitorsFromSportEvent(item, culture)) { saved = true; } else { LogSavingDtoConflict(id, typeof(StageDTO), item.GetType()); } break; case DtoType.TournamentInfo: if (SaveCompetitorsFromSportEvent(item, culture)) { saved = true; } else { LogSavingDtoConflict(id, typeof(TournamentInfoDTO), item.GetType()); } break; case DtoType.SportEventSummary: if (SaveCompetitorsFromSportEvent(item, culture)) { saved = true; } else { LogSavingDtoConflict(id, typeof(SportEventSummaryDTO), item.GetType()); } break; case DtoType.Sport: break; case DtoType.Category: break; case DtoType.Tournament: break; case DtoType.PlayerProfile: var playerProfile = item as PlayerProfileDTO; if (playerProfile != null) { AddPlayerProfile(playerProfile, null, culture, true); saved = true; } else { LogSavingDtoConflict(id, typeof(PlayerProfileDTO), item.GetType()); } break; case DtoType.Competitor: var competitor = item as CompetitorDTO; if (competitor != null) { AddCompetitor(id, competitor, culture, true); saved = true; } else { LogSavingDtoConflict(id, typeof(CompetitorDTO), item.GetType()); } break; case DtoType.CompetitorProfile: var competitorProfile = item as CompetitorProfileDTO; if (competitorProfile != null) { AddCompetitorProfile(id, competitorProfile, culture, true); saved = true; } else { LogSavingDtoConflict(id, typeof(CompetitorProfileDTO), item.GetType()); } break; case DtoType.SimpleTeamProfile: var simpleTeamProfile = item as SimpleTeamProfileDTO; if (simpleTeamProfile != null) { AddCompetitorProfile(id, simpleTeamProfile, culture, true); saved = true; } else { LogSavingDtoConflict(id, typeof(SimpleTeamProfileDTO), item.GetType()); } break; case DtoType.MarketDescription: break; case DtoType.SportEventStatus: break; case DtoType.MatchTimeline: var matchTimeline = item as MatchTimelineDTO; if (matchTimeline != null) { saved = SaveCompetitorsFromSportEvent(matchTimeline.SportEvent, culture); } else { LogSavingDtoConflict(id, typeof(MatchTimelineDTO), item.GetType()); } break; case DtoType.TournamentSeasons: break; case DtoType.Fixture: if (SaveCompetitorsFromSportEvent(item, culture)) { saved = true; } else { LogSavingDtoConflict(id, typeof(FixtureDTO), item.GetType()); } break; case DtoType.SportList: break; case DtoType.SportEventSummaryList: break; case DtoType.MarketDescriptionList: break; case DtoType.VariantDescription: break; case DtoType.VariantDescriptionList: break; case DtoType.Lottery: break; case DtoType.LotteryDraw: break; case DtoType.LotteryList: break; case DtoType.BookingStatus: break; case DtoType.SportCategories: break; case DtoType.AvailableSelections: break; case DtoType.TournamentInfoList: break; default: ExecutionLog.LogWarning($"Trying to add unchecked dto type: {dtoType} for id: {id}."); break; } return(saved); }
/// <summary> /// Asynchronously gets the <see cref="MarketDescriptionCacheItem"/> specified by it's id. If the item is not found in local cache, all items for specified /// language are fetched from the service and stored/merged into the local cache. /// </summary> /// <param name="id">The id of the <see cref="MarketDescriptionCacheItem"/> instance to get</param> /// <param name="cultures">A <see cref="IEnumerable{CultureInfo}"/> specifying the languages which the returned item must contain</param> /// <returns>A <see cref="Task"/> representing the async operation</returns> /// <exception cref="CommunicationException">An error occurred while accessing the remote party</exception> /// <exception cref="DeserializationException">An error occurred while deserializing fetched data</exception> /// <exception cref="FormatException">An error occurred while mapping deserialized entities</exception> private async Task <MarketDescriptionCacheItem> GetMarketInternalAsync(int id, IEnumerable <CultureInfo> cultures) { Guard.Argument(cultures, nameof(cultures)).NotNull().NotEmpty(); var cultureList = cultures as List <CultureInfo> ?? cultures.ToList(); MarketDescriptionCacheItem description; if ((description = GetItemFromCache(id)) != null && !LanguageHelper.GetMissingCultures(cultureList, description.FetchedLanguages).Any()) { return(description); } try { if (_isDisposed) { return(null); } //WriteLog($"Prefetching invariant market description for id={id} and langs: [{string.Join(",", cultureList.Select(s => s.TwoLetterISOLanguageName))}]."); await _semaphore.WaitAsync().ConfigureAwait(false); description = GetItemFromCache(id); var missingLanguages = LanguageHelper.GetMissingCultures(cultureList, description?.FetchedLanguages).ToList(); if (missingLanguages.Any()) { // dont call for already fetched languages missingLanguages = LanguageHelper.GetMissingCultures(missingLanguages, _fetchedLanguages).ToList(); } if (!missingLanguages.Any()) { return(description); } //WriteLog($"Actually fetching invariant market description for id={id} and langs:[{string.Join(",", missingLanguages.Select(s => s.TwoLetterISOLanguageName))}]."); var cultureTaskDictionary = missingLanguages.ToDictionary(l => l, l => _dataRouterManager.GetMarketDescriptionsAsync(l)); await Task.WhenAll(cultureTaskDictionary.Values).ConfigureAwait(false); //WriteLog($"Actually fetching invariant market description for id={id} and langs:[{string.Join(",", missingLanguages.Select(s => s.TwoLetterISOLanguageName))}] COMPLETED."); //missingLanguages.ForEach(s => _fetchedLanguages.Add(s)); } catch (Exception ex) { var disposedException = ex as ObjectDisposedException; if (disposedException != null) { ExecutionLog.LogWarning($"An error occurred while fetching market descriptions because the object graph is being disposed. Object causing the exception: {disposedException.ObjectName}."); return(null); } throw; } finally { if (!_isDisposed) { _semaphore.Release(); } } description = GetItemFromCache(id); return(description != null && !LanguageHelper.GetMissingCultures(cultureList, description.FetchedLanguages).Any() ? description : null); }
/// <summary> /// Adds the dto item to cache /// </summary> /// <param name="id">The identifier of the object</param> /// <param name="item">The item</param> /// <param name="culture">The culture</param> /// <param name="dtoType">Type of the dto</param> /// <param name="requester">The cache item which invoked request</param> /// <returns><c>true</c> if added, <c>false</c> otherwise</returns> protected override bool CacheAddDtoItem(URN id, object item, CultureInfo culture, DtoType dtoType, ISportEventCI requester) { Guard.Argument(id, nameof(id)).NotNull(); Guard.Argument(item, nameof(item)).NotNull(); if (_isDisposed) { return(false); } var saved = false; switch (dtoType) { case DtoType.Category: break; case DtoType.Competitor: break; case DtoType.CompetitorProfile: break; case DtoType.SimpleTeamProfile: break; case DtoType.Fixture: var fixtureDTO = item as FixtureDTO; if (fixtureDTO != null) { if (fixtureDTO.SportEventStatus != null) { AddSportEventStatus(id, new SportEventStatusCI(null, fixtureDTO.SportEventStatus), fixtureDTO.StatusOnEvent, "Fixture"); } saved = true; } else { LogSavingDtoConflict(id, typeof(FixtureDTO), item.GetType()); } break; case DtoType.MarketDescription: break; case DtoType.MatchSummary: var matchDTO = item as MatchDTO; if (matchDTO != null) { if (matchDTO.SportEventStatus != null) { AddSportEventStatus(id, new SportEventStatusCI(null, matchDTO.SportEventStatus), matchDTO.StatusOnEvent, "Match"); } saved = true; } else { LogSavingDtoConflict(id, typeof(MatchDTO), item.GetType()); } break; case DtoType.MatchTimeline: var matchTimelineDTO = item as MatchTimelineDTO; if (matchTimelineDTO != null) { if (matchTimelineDTO.SportEventStatus != null) { AddSportEventStatus(id, new SportEventStatusCI(null, matchTimelineDTO.SportEventStatus), matchTimelineDTO.SportEvent.StatusOnEvent, "MatchTimeline"); } saved = true; } else { LogSavingDtoConflict(id, typeof(MatchTimelineDTO), item.GetType()); } break; case DtoType.PlayerProfile: break; case DtoType.RaceSummary: var stageDTO = item as StageDTO; if (stageDTO != null) { if (stageDTO.SportEventStatus != null) { AddSportEventStatus(id, new SportEventStatusCI(null, stageDTO.SportEventStatus), stageDTO.StatusOnEvent, "Stage"); } saved = true; } else { LogSavingDtoConflict(id, typeof(StageDTO), item.GetType()); } break; case DtoType.Sport: break; case DtoType.SportList: break; case DtoType.SportEventStatus: var sportEventStatusDTO = item as SportEventStatusDTO; if (sportEventStatusDTO != null) { AddSportEventStatus(id, new SportEventStatusCI(sportEventStatusDTO, null), sportEventStatusDTO.Status.ToString(), "OddsChange"); saved = true; } else { LogSavingDtoConflict(id, typeof(SportEventStatusDTO), item.GetType()); } break; case DtoType.SportEventSummary: var competitionDTO = item as CompetitionDTO; if (competitionDTO != null) { if (competitionDTO.SportEventStatus != null) { AddSportEventStatus(id, new SportEventStatusCI(null, competitionDTO.SportEventStatus), competitionDTO.StatusOnEvent, "SportEventSummary"); } saved = true; } break; case DtoType.SportEventSummaryList: var summaryList = item as EntityList <SportEventSummaryDTO>; if (summaryList != null) { foreach (var s in summaryList.Items) { var compDTO = s as CompetitionDTO; if (compDTO?.SportEventStatus != null) { AddSportEventStatus(id, new SportEventStatusCI(null, compDTO.SportEventStatus), s.StatusOnEvent, "SportEventSummaryList"); } } saved = true; } else { LogSavingDtoConflict(id, typeof(EntityList <SportEventSummaryDTO>), item.GetType()); } break; case DtoType.Tournament: break; case DtoType.TournamentInfo: break; case DtoType.TournamentSeasons: break; case DtoType.MarketDescriptionList: break; case DtoType.VariantDescription: break; case DtoType.VariantDescriptionList: break; case DtoType.Lottery: break; case DtoType.LotteryDraw: break; case DtoType.LotteryList: break; case DtoType.BookingStatus: break; case DtoType.SportCategories: break; case DtoType.AvailableSelections: break; case DtoType.TournamentInfoList: break; default: ExecutionLog.LogWarning($"Trying to add unchecked dto type: {dtoType} for id: {id}."); break; } //CacheLog.LogDebug($"Saving {id} COMPLETED. Saved={saved}."); return(saved); }
/// <summary> /// Merges the provided descriptions with those found in cache /// </summary> /// <param name="culture">A <see cref="CultureInfo"/> specifying the language of the <code>descriptions</code></param> /// <param name="descriptions">A <see cref="IEnumerable{MarketDescriptionDTO}"/> containing market descriptions in specified language</param> private void Merge(CultureInfo culture, IEnumerable <MarketDescriptionDTO> descriptions) { Guard.Argument(culture, nameof(culture)).NotNull(); Guard.Argument(descriptions, nameof(descriptions)).NotNull().NotEmpty(); var descriptionList = descriptions as List <MarketDescriptionDTO> ?? descriptions.ToList(); try { _semaphoreCacheMerge.Wait(); foreach (var marketDescription in descriptionList) { try { var cachedItem = _cache.GetCacheItem(marketDescription.Id.ToString()); if (cachedItem == null) { cachedItem = new CacheItem(marketDescription.Id.ToString(), MarketDescriptionCacheItem.Build(marketDescription, _mappingValidatorFactory, culture, CacheName)); _cache.Add(cachedItem, _cacheItemPolicy); } else { ((MarketDescriptionCacheItem)cachedItem.Value).Merge(marketDescription, culture); } } catch (Exception e) { if (!(e is InvalidOperationException)) { throw; } ExecutionLog.LogWarning($"Mapping validation for MarketDescriptionCacheItem failed. Id={marketDescription.Id}", e); } } _fetchedLanguages.Add(culture); } finally { if (!_isDisposed) { _semaphoreCacheMerge.Release(); } } //var c = _cache.Count(); //ExecutionLog.LogDebug($"InvariantMarketDescriptionCache count: {c}."); //foreach (var keyValue in _cache.Where(s=>s.Key != null)) //{ // var ci = (MarketDescriptionCacheItem)keyValue.Value; // if (ci.Mappings != null) // { // foreach (var mapping in ci.Mappings) // { // if (mapping.OutcomeMappings != null) // { // foreach (var outcomeMapping in mapping.OutcomeMappings) // { // if (outcomeMapping.ProducerOutcomeNames.Count != ci.FetchedLanguages.Count) // { // ExecutionLog.LogError($"Market {ci.Id}: problem with outcome mapping {outcomeMapping.OutcomeId} and mapped marketId {outcomeMapping.MarketId}"); // } // } // } // } // } //} //var cacheItem = _cache.First(); }
/// <summary> /// Adds the dto item to cache /// </summary> /// <param name="id">The identifier of the object</param> /// <param name="item">The item</param> /// <param name="culture">The culture</param> /// <param name="dtoType">Type of the dto</param> /// <param name="requester">The cache item which invoked request</param> /// <returns><c>true</c> if added, <c>false</c> otherwise</returns> protected override async Task <bool> CacheAddDtoItemAsync(URN id, object item, CultureInfo culture, DtoType dtoType, ISportEventCI requester) { if (_isDisposed) { return(false); } var saved = false; switch (dtoType) { case DtoType.MatchSummary: var competitorsSaved1 = await SaveCompetitorsFromSportEventAsync(item, culture).ConfigureAwait(false); if (competitorsSaved1) { saved = true; } else { LogSavingDtoConflict(id, typeof(MatchDTO), item.GetType()); } break; case DtoType.RaceSummary: var competitorsSaved2 = await SaveCompetitorsFromSportEventAsync(item, culture).ConfigureAwait(false); if (competitorsSaved2) { saved = true; } else { LogSavingDtoConflict(id, typeof(StageDTO), item.GetType()); } break; case DtoType.TournamentInfo: var competitorsSaved3 = await SaveCompetitorsFromSportEventAsync(item, culture).ConfigureAwait(false); if (competitorsSaved3) { saved = true; } else { LogSavingDtoConflict(id, typeof(TournamentInfoDTO), item.GetType()); } break; case DtoType.SportEventSummary: var competitorsSaved4 = await SaveCompetitorsFromSportEventAsync(item, culture).ConfigureAwait(false); if (competitorsSaved4) { saved = true; } else { LogSavingDtoConflict(id, typeof(SportEventSummaryDTO), item.GetType()); } break; case DtoType.Sport: break; case DtoType.Category: break; case DtoType.Tournament: break; case DtoType.PlayerProfile: var playerProfile = item as PlayerProfileDTO; if (playerProfile != null) { await AddPlayerProfileAsync(playerProfile, null, culture, true).ConfigureAwait(false); saved = true; } else { LogSavingDtoConflict(id, typeof(PlayerProfileDTO), item.GetType()); } break; case DtoType.Competitor: var competitor = item as CompetitorDTO; if (competitor != null) { await AddCompetitorAsync(id, competitor, culture, true).ConfigureAwait(false); saved = true; } else { LogSavingDtoConflict(id, typeof(CompetitorDTO), item.GetType()); } break; case DtoType.CompetitorProfile: var competitorProfile = item as CompetitorProfileDTO; if (competitorProfile != null) { await AddCompetitorProfileAsync(id, competitorProfile, culture, true).ConfigureAwait(false); saved = true; } else { LogSavingDtoConflict(id, typeof(CompetitorProfileDTO), item.GetType()); } break; case DtoType.SimpleTeamProfile: var simpleTeamProfile = item as SimpleTeamProfileDTO; if (simpleTeamProfile != null) { await AddCompetitorProfileAsync(id, simpleTeamProfile, culture, true).ConfigureAwait(false); saved = true; } else { LogSavingDtoConflict(id, typeof(SimpleTeamProfileDTO), item.GetType()); } break; case DtoType.MarketDescription: break; case DtoType.SportEventStatus: break; case DtoType.MatchTimeline: var matchTimeline = item as MatchTimelineDTO; if (matchTimeline != null) { saved = await SaveCompetitorsFromSportEventAsync(matchTimeline.SportEvent, culture).ConfigureAwait(false); } else { LogSavingDtoConflict(id, typeof(MatchTimelineDTO), item.GetType()); } break; case DtoType.TournamentSeasons: var tournamentSeason = item as TournamentSeasonsDTO; if (tournamentSeason?.Tournament != null) { await SaveCompetitorsFromSportEventAsync(tournamentSeason.Tournament, culture).ConfigureAwait(false); saved = true; } break; case DtoType.Fixture: var competitorsSaved5 = await SaveCompetitorsFromSportEventAsync(item, culture).ConfigureAwait(false); if (competitorsSaved5) { saved = true; } else { LogSavingDtoConflict(id, typeof(FixtureDTO), item.GetType()); } break; case DtoType.SportList: break; case DtoType.SportEventSummaryList: var sportEventSummaryList = item as EntityList <SportEventSummaryDTO>; if (sportEventSummaryList != null) { var tasks = sportEventSummaryList.Items.Select(s => SaveCompetitorsFromSportEventAsync(s, culture)); await Task.WhenAll(tasks).ConfigureAwait(false); saved = true; } else { LogSavingDtoConflict(id, typeof(SportEventSummaryDTO), item.GetType()); } break; case DtoType.MarketDescriptionList: break; case DtoType.VariantDescription: break; case DtoType.VariantDescriptionList: break; case DtoType.Lottery: break; case DtoType.LotteryDraw: break; case DtoType.LotteryList: break; case DtoType.BookingStatus: break; case DtoType.SportCategories: break; case DtoType.AvailableSelections: break; case DtoType.TournamentInfoList: var ts = item as EntityList <TournamentInfoDTO>; if (ts != null) { var tasks = ts.Items.Select(s => SaveCompetitorsFromSportEventAsync(s, culture)); await Task.WhenAll(tasks).ConfigureAwait(false); saved = true; } else { LogSavingDtoConflict(id, typeof(EntityList <TournamentInfoDTO>), item.GetType()); } break; default: ExecutionLog.LogWarning($"Trying to add unchecked dto type: {dtoType} for id: {id}."); break; } return(saved); }