Дедлоки редко проявляются в ходе разработки, но часто всплывают под реальной нагрузкой в продакшне. Дедлок — ситуация, когда две или более сессии базы данных блокируют друг друга, ожидая освобождения ресурсов.
В итоге SQL Server прерывает одну из транзакций:
SqlException: Transaction (Process ID xx) was deadlocked on resources...
Пример простого дедлока: два контекста одновременно меняют одну строку и пытаются сохранить изменения. Один запрос блокирует строку, второй вызывает дедлок.
await using var context1 = new AppDbContext();
await using var context2 = new AppDbContext();
var order1 = await context1.Orders.FindAsync(1);
var order2 = await context2.Orders.FindAsync(1);
order1.Status = "Paid";
order2.Status = "Shipped";
await context1.SaveChangesAsync(); // Блокирует строку
await context2.SaveChangesAsync(); // Возможен deadlock
Стратегии предотвращения
• Короткие транзакции
Минимизируйте работу внутри транзакции:
await using var tx = await context.Database.BeginTransactionAsync();
var order = await context.Orders.FindAsync(orderId);
order.Status = "Paid";
await context.SaveChangesAsync();
await tx.CommitAsync();
Избегайте сетевых вызовов и посторонних запросов перед коммитом.
• Правильные индексы
Отсутствие индексов приводит к сканированию таблиц и длительным блокировкам. Используйте SQL Profiler для мониторинга.
• Оптимальный уровень изоляции
ReadCommitted обычно достаточен для большинства операций:
await using var tx = await context.Database.BeginTransactionAsync(
IsolationLevel.ReadCommitted);
• Логика повторов
Используйте встроенную политику retry в EF Core:
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(connectionString, sql =>
sql.EnableRetryOnFailure(
maxRetryCount: 3,
maxRetryDelay: TimeSpan.FromSeconds(5),
errorNumbersToAdd: null)));
• RowVersion для контроля конкурентности
public class Order
{
public int Id { get; set; }
public string Status { get; set; }
[Timestamp]
public byte[] RowVersion { get; set; }
}
EF Core выбросит
DbUpdateConcurrencyException при конфликте изменений.Дедлоки не баги, а следствие паттернов конкурентного доступа.
#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍6
Повышение надёжности .NET-приложений: как обрабатывать сбои и предотвращать каскадные ошибки.
Даже самые стабильные системы ломаются — вопрос лишь в том, насколько вы готовы к этому. Библиотека Polly позволяет гибко управлять сбоями и повышать устойчивость микросервисов и API.
На открытом вебинаре курса OTUS C# ASP.NET Core разработчик Виктор Дзицкий покажет, как использовать Polly и HttpClientFactory для защиты приложений от временных отказов и непредсказуемых сетевых ошибок.
📌 6 ноября, 20:00
Повышение надежности .NET-приложений с Polly
— ключевые стратегии и политики Polly
— настройка и комбинирование стратегий для сложных сценариев
— защита от каскадных сбоев и готовые паттерны устойчивости
— улучшения в .NET 8
Вебинар бесплатный и подойдёт .NET-разработчикам, работающим с микросервисами и внешними API, которые хотят сделать свои системы по-настоящему отказоустойчивыми.
👉 Регистрируйтесь: https://clc.to/zyj9ow
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
Даже самые стабильные системы ломаются — вопрос лишь в том, насколько вы готовы к этому. Библиотека Polly позволяет гибко управлять сбоями и повышать устойчивость микросервисов и API.
На открытом вебинаре курса OTUS C# ASP.NET Core разработчик Виктор Дзицкий покажет, как использовать Polly и HttpClientFactory для защиты приложений от временных отказов и непредсказуемых сетевых ошибок.
📌 6 ноября, 20:00
Повышение надежности .NET-приложений с Polly
— ключевые стратегии и политики Polly
— настройка и комбинирование стратегий для сложных сценариев
— защита от каскадных сбоев и готовые паттерны устойчивости
— улучшения в .NET 8
Вебинар бесплатный и подойдёт .NET-разработчикам, работающим с микросервисами и внешними API, которые хотят сделать свои системы по-настоящему отказоустойчивыми.
👉 Регистрируйтесь: https://clc.to/zyj9ow
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
❤1
Разбираем 14 вопросов, которые лучше не задавать на собеседовании: что не так с каждым из них и как переформулировать, чтобы получить нужную информацию без риска для репутации.
Please open Telegram to view this post
VIEW IN TELEGRAM
🥱8👍5😁3
Даже самая оптимизированная система не застрахована от deadlock на 100%. При высоких нагрузках, пиковых моментах или редких edge-case сценариях они всё равно могут возникнуть. Важно не предотвращение на 100% (это невозможно), а грамотное восстановление.
• Умный ретрай с экспоненциальной задержкой
Простой повтор без задержки только усугубит ситуацию. Используйте экспоненциальную задержку:
public async Task<bool> SaveWithRetryAsync(DbContext context, int maxRetries = 3)
{
for (int attempt = 0; attempt < maxRetries; attempt++)
{
try
{
await context.SaveChangesAsync();
return true;
}
catch (DbUpdateException ex) when (IsDeadlock(ex))
{
if (attempt == maxRetries - 1)
throw;
// Экспоненциальная задержка: 100ms, 200ms, 400ms
var delay = TimeSpan.FromMilliseconds(100 * Math.Pow(2, attempt));
await Task.Delay(delay);
Console.WriteLine($"Deadlock detected, retry {attempt + 1}/{maxRetries}");
}
}
return false;
}
bool IsDeadlock(Exception ex) =>
ex.InnerException is SqlException sqlEx &&
(sqlEx.Number == 1205 || // Deadlock victim
ex.InnerException.Message.Contains("deadlocked"));
• Ограничение параллелизма
Если ваше приложение обрабатывает большие пакеты данных, ограничьте количество одновременных операций:
public class OrderProcessor
{
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(5); // Макс 5 одновременно
public async Task ProcessOrdersAsync(List<int> orderIds)
{
var tasks = orderIds.Select(id => ProcessWithSemaphoreAsync(id));
await Task.WhenAll(tasks);
}
private async Task ProcessWithSemaphoreAsync(int orderId)
{
await _semaphore.WaitAsync();
try
{
await using var context = new AppDbContext();
var order = await context.Orders.FindAsync(orderId);
order.Status = "Processed";
await SaveWithRetryAsync(context);
}
finally
{
_semaphore.Release();
}
}
}
• Логирование и анализ
Недостаточно просто повторить — нужно понять причину:
catch (DbUpdateException ex) when (IsDeadlock(ex))
{
_logger.LogWarning(ex,
"Deadlock on order {OrderId}, attempt {Attempt}/{MaxAttempts}",
orderId, attempt + 1, maxRetries);
// Отправьте метрику в мониторинг
_telemetry.TrackMetric("Deadlocks", 1, new Dictionary<string, string>
{
["Entity"] = "Order",
["Operation"] = "Update"
});
}
• Захват графов блокировок
SQL Server создаёт подробные графы взаимоблокировок. Настройте их захват:
-- Extended Events для захвата deadlock
CREATE EVENT SESSION [DeadlockMonitoring] ON SERVER
ADD EVENT sqlserver.xml_deadlock_report
ADD TARGET package0.event_file(SET filename = N'C:\Logs\Deadlocks.xel')
WITH (MAX_MEMORY = 4096 KB, EVENT_RETENTION_MODE = ALLOW_SINGLE_EVENT_LOSS);
ALTER EVENT SESSION [DeadlockMonitoring] ON SERVER STATE = START;
Сочетание правильного предотвращения и надежного восстановления создаст устойчивую систему, способную справиться с любыми нагрузками.
Чтобы строить надёжные решения нужно знать архитектуру и уметь её спроектировать. Для этого можно пройти наш интенсив по архитектуре и шаблонам проектирования. Осталось всего 3 дня скидок!
#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
❤17👍5🔥4
.NET-разработчик на удалёнку.
Backend-developer в Москве от 200 000 ₽.
.NET Developer от 200 000 ₽ с удалёнкой.
Бустер — Удалённо (в любом городе мира).
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2👍2🥱1
Когда файл огромный, главное — не тянуть всё в память.
Пример:
var errors = File.ReadLines(logPath).Where(l => l.Contains("ERROR"));ReadLines читает файл построчно, не загружая всё сразу.Не добавляйте
.ToList(), если хочется сохранить ленивость — иначе всё материализуется в памяти.#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13❤1
🎃 Хэллоуин в Proglib Academy: скидки, призы и... немного паники
Сегодня 31 октября, и это не просто время тыкв и призраков, это ПОСЛЕДНИЙ ДЕНЬ, когда ты можешь выиграть макбук!
→ Купи любой курс со скидкой 40% 💸
→ Начни обучение, чтобы пройти 2 недели к 15 ноября 🎓
→ Напиши куратору #розыгрыш ✍️
Всё! Теперь ты в игре.
👉 Сейчас или никогда!
Сегодня 31 октября, и это не просто время тыкв и призраков, это ПОСЛЕДНИЙ ДЕНЬ, когда ты можешь выиграть макбук!
→ Купи любой курс со скидкой 40% 💸
→ Начни обучение, чтобы пройти 2 недели к 15 ноября 🎓
→ Напиши куратору #розыгрыш ✍️
Всё! Теперь ты в игре.
👉 Сейчас или никогда!
Сегодня день, когда можно немного отвлечься от кода и рутины. Костюм помогает прочувствовать праздник, даже если это всего один день.
💬 Делитесь, кто в костюме сегодня, оставляйте свои истории 👇
#entry_point
Please open Telegram to view this post
VIEW IN TELEGRAM
Вам дан массив nums длиной n+2, содержащий числа от 0 до n-1. Два числа случайным образом появились в списке дважды. Нужно вернуть эти два числа. Например, для входа
[0][1][1][2][3][3][4] ответ будет [1][3].Для решения можно воспользоваться подсчётом количества появлений каждого числа.
Если встретили число во второй раз — записываем его в ответ:
public int[] GetSneakyNumbers(int[] nums)
{
int n = nums.Length;
int[] count = new int[101];
int[] res = new int[2];
int idx = 0;
foreach (var num in nums)
{
count[num]++;
if (count[num] == 2)
{
res[idx] = num;
idx++;
}
}
return res;
}
При помощи вспомогательного массива считаем, сколько раз встречается каждое число, и когда оно появилось второй раз — запоминаем.
#dotnet_challenge
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7🥱4😁1
Please open Telegram to view this post
VIEW IN TELEGRAM
😁37👍1🤔1
В зарплатных переговорах нет универсального сценария. Но есть проверенные стратегии под разные ситуации.
В статье 9 тактик от открытой до «я никуда не тороплюсь» — с готовыми фразами для собеседования.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Шестидневная рабочая неделя подошла к концу, и наконец-то время расслабиться. Используйте свободное время для восстановления и новых впечатлений.
#entry_point
Please open Telegram to view this post
VIEW IN TELEGRAM
💯9😁1
📰 Шестидневные новости
Вспомним, что произошло за 6 рабочих дней.
— C# сохраняет популярность
Вышел ежегодный Octoverse от GitHub, в котором отмечается рекордный рост числа разработчиков, активность в проектах с AI и смена лидерства по языкам программирования.
— Unity Lite. Простой старт в 3D для всех
Инструмент от Unity для создания интерактивных 3D-сцен без программирования, с удобной навигацией и редактором внутри браузера/.
— Нейросети поиграли в покер
Победителем стала модель OpenAI o3 с выигрышем в $36,691 виртуальных денег. Второе место занял Claude Sonnet 4.5, а третье — Grok 4
— Новые кастомные агенты Copilot для .NET
GitHub запускает интеллектуальных помощников для оптимизации рабочего процесса .NET‑разработчиков.
— Звуки флоппи-дисководов в эмуляторе
🐸 Библиотека шарписта
#async_news
Вспомним, что произошло за 6 рабочих дней.
— C# сохраняет популярность
Вышел ежегодный Octoverse от GitHub, в котором отмечается рекордный рост числа разработчиков, активность в проектах с AI и смена лидерства по языкам программирования.
— Unity Lite. Простой старт в 3D для всех
Инструмент от Unity для создания интерактивных 3D-сцен без программирования, с удобной навигацией и редактором внутри браузера/.
— Нейросети поиграли в покер
Победителем стала модель OpenAI o3 с выигрышем в $36,691 виртуальных денег. Второе место занял Claude Sonnet 4.5, а третье — Grok 4
— Новые кастомные агенты Copilot для .NET
GitHub запускает интеллектуальных помощников для оптимизации рабочего процесса .NET‑разработчиков.
— Звуки флоппи-дисководов в эмуляторе
#async_news
Please open Telegram to view this post
VIEW IN TELEGRAM
Anonymous Poll
26%
Как торговаться о зарплате
32%
Мемы
33%
Задачка с собеса
23%
Ленивый фильтры
29%
Два поста про дедлоки
14%
Звуки флоппи дисководов
🤔2
Please open Telegram to view this post
VIEW IN TELEGRAM
🥱12😁11🌚1
Каждый разработчик сталкивался с необходимостью выполнять долгие операции в фоне: отправка писем, обработка платежей, генерация отчётов, синхронизация данных.
Обычно первая мысль — взять Hangfire, Quartz или Azure Functions. Но .NET 9 предоставляет встроенные примитивы, которые отлично справляются с этой задачей самостоятельно.
Традиционные подходы — блокирующая коллекция и самописные очереди имеют недостатки: требуют ручной синхронизации, рискуют блокировкой потоков, не имеют встроенной поддержки обратного давления.
Реализуем очередь задач с помощью каналов и фоновые сервисы
Интерфейс и реализация очереди:
public interface IBackgroundTaskQueue
{
ValueTask QueueAsync(Func<CancellationToken, Task> workItem);
ValueTask<Func<CancellationToken, Task>> DequeueAsync(CancellationToken cancellationToken);
}
public class BackgroundTaskQueue : IBackgroundTaskQueue
{
private readonly Channel<Func<CancellationToken, Task>> _queue;
public BackgroundTaskQueue(int capacity = 100)
{
var options = new BoundedChannelOptions(capacity)
{
SingleReader = false,
SingleWriter = false,
FullMode = BoundedChannelFullMode.Wait
};
_queue = Channel.CreateBounded<Func<CancellationToken, Task>>(options);
}
public async ValueTask QueueAsync(Func<CancellationToken, Task> workItem)
=> await _queue.Writer.WriteAsync(workItem);
public async ValueTask<Func<CancellationToken, Task>> DequeueAsync(CancellationToken cancellationToken)
=> await _queue.Reader.ReadAsync(cancellationToken);
}
Фоновые сервисы для обработки:
public class BackgroundWorker : BackgroundService
{
private readonly IBackgroundTaskQueue _taskQueue;
private readonly ILogger<BackgroundWorker> _logger;
public BackgroundWorker(IBackgroundTaskQueue taskQueue, ILogger<BackgroundWorker> logger)
{
_taskQueue = taskQueue;
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Фоновый worker запущен");
while (!stoppingToken.IsCancellationRequested)
{
var workItem = await _taskQueue.DequeueAsync(stoppingToken);
try
{
await workItem(stoppingToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка при выполнении задачи");
}
}
_logger.LogInformation("Worker останавливается...");
}
}
Использование в контроллере:
app.MapPost("/send-email", async (IBackgroundTaskQueue queue) =>
{
await queue.QueueAsync(async token =>
{
await Task.Delay(1000, token); // имитация отправки
Console.WriteLine($"Email отправлен в {DateTime.UtcNow}");
});
return Results.Accepted();
});Запрос возвращается немедленно, а работа продолжается в фоне. Queue автоматически буферизирует задачи, управляет нагрузкой и применяет обратное давление, если очередь переполнится.
Когда использовать этот подход
Подходит:
• Внутренняя обработка задач в приложении
• Нет нужды в UI-панели мониторинга
• Self-contained сервисы
Возьмите библиотеку, если:
• Нужна распределённая обработка
• Требуется веб-интерфейс для управления
• Задачи должны пережить перезагрузку приложения
#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12
Дано целое число, нужно проверить, является ли оно полным квадратом.
Первый рефлекс новичка — взять квадратный корень и проверить, целое ли число:
(int)Math.Sqrt(num) * (int)Math.Sqrt(num) == num
Но на собесе после этого последует вопрос: «А можете без встроенной функции?» Вот тогда начинается интересное.
Вместо математики используем логику: если x * x = num, то x находится где-то между 1 и num. Сужаем диапазон поиска, пока не найдём точный ответ.
public bool IsPerfectSquare(int num)
{
long left = 1;
long right = num;
while (left <= right)
{
long mid = (left + right) / 2;
long square = mid * mid;
if (square == num)
return true;
else if (square < num)
left = mid + 1;
else
right = mid - 1;
}
return false;
}
Есть ещё метод Ньютона для поиска корня — он даже быстрее для больших чисел:
public bool IsPerfectSquare(int num)
{
long x = num;
while (x * x > num)
{
x = (x + num / x) / 2;
}
return x * x == num;
}
Главное: объясните почему вы выбрали именно этот подход, а не просто скопировали решение. На собесе вас оценивают не только по скорости, а по способности мыслить.
#dotnet_challenge
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤2
Если вы работаете с авторизацией в .NET и используете Identity, но всё ещё не совсем понимаете, как правильно организовать систему разрешений — есть видео, которое стоит посмотреть.
В нём конкретный пример: как взять стандартный ASP.NET Core Identity и использовать его для управления доступом. Ничего экзотического — обычная setup с JWT и кастомным authorization handler.
#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12
Завтра начнётся самая короткая рабочая неделя ноября. Это буквально понедельник, среда и пятница. После шестидневки самое то.
💬 Что будете делать? Успевать выполнить недельные обязанности за три дня? Или три дня будете пытаться начать работать?
#entry_point
Please open Telegram to view this post
VIEW IN TELEGRAM
Бывает, нужно быстро собрать, запустить или опубликовать проект без запуска тяжелой IDE, особенно в пайплайне или на сервере разработчика. Для этого хватает нескольких команд из .NET CLI, которые работают одинаково на всех платформах.
Проверить установку и окружение поможет команда
dotnet --info, она покажет версии SDK и рантаймов и архитектуру хоста.Сборка проекта выполняется командой
dotnet build, по умолчанию в конфигурации Debug и с выводом артефактов в bin, причем команда учитывает инкрементальные изменения для скорости.Запуск приложения через
dotnet run объединяет сборку и старт процесса, что эквивалентно кнопке Run в IDE и удобно для ручных проверок локально.Горячая перезагрузка из терминала через
dotnet watch отслеживает изменения файлов и повторно запускает приложение с Hot Reload без ручного рестарта, что ускоряет цикл правка и проверка.Если сборка ведет себя странно, стоит выполнить
dotnet clean, чтобы удалить выходные артефакты и заставить следующий build собрать все заново.Для развертывания используйте
dotnet publish, который соберет релиз и положит готовый к деплою набор файлов в папку publish, включая веб приложения и сервисы.#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4
