Назад к задачам
Junior — Senior
13

Обнаружение проблемы синхронизации в многопоточном сервисе

Получайте помощь с лайвкодингом в реальном времени с Sobes Copilot
Условие задачи

Дан класс FlatteningService, содержащий несколько полей‑коллекций, в частности Dictionary<string, IList<FlattenLocationFilter>> locationFilters. Внутри метода MakeFlatten происходит чтение и запись в эту словарную структуру. При одновременных вызовах метода из десяти потоков могут возникать исключения типа KeyNotFoundException и другие связанные с доступом к словарю. Важно понять, почему при проверке наличия ключа через ContainsKey и последующем добавлении через Add появляется ошибка «ключ уже существует», а последующее обращение к locationFilters[locationFilter] приводит к KeyNotFoundException. Найдите и опишите источник проблемы.

public class FlatteningService
{
    private readonly Dictionary<string, IList<FlattenLocationFilter>> locationFilters;

    public PromoFlatteningService()
    {
        locationFilters = new Dictionary<string, IList<FlattenLocationFilter>>();
    }

    public IEnumerable<FlattenPromo> MakeFlatten(IEnumerable<OraclePromo> items)
    {
        var itemsList = items.ToLookup(x => x.PromoCode);

        var flatList = new List<FlattenPromo>();

        foreach (var src in itemsList.Single())
        {
            var promoCode = $"{src.PromoCode}";

            const string locationFilter = "Auchan";
            if (!locationFilters.ContainsKey(locationFilter))
            {
                // выходит ошибка, что ключ уже существует
                locationFilters.Add(locationFilter, new List<FlattenLocationFilter>
                {
                    new()
                    {
                        FilterCode = locationFilter,
                        FilterOperator = "AND",
                        CriteriaCode = "Location",
                        CriteriaOperator = "OR",
                        ExpectedValue = "Auchan",
                        ExpectedOperator = "EQ",
                        FilterDescription = "none",
                        LocationPropertyCode = "none"
                    }
                });

                flatlist.Add(new FlattenPromo
        {
            PromoCode = promoCode,
            PromoBegin = src.StartDate.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc),
            PromoEnd = src.EndDate.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc),
            LocationFilterCode = locationFilter,
            LocationFilter = locationFilters[locationFilter], // выходит ошибка keyNotFoundException
            ProductCode = src.ProductId,
            ProductDiscountPercent = src.DiscountPercent,
            ProductPlanQuantity = src.PlanSum,
        });
            }
        }
    }
}