C#-разработчик? Пора осваивать AI-агентов
Экосистема
Начинаем сегодня в 19:00 МСК.
Основные темы:
— путь от базовых промптов до мультиагентных систем;
— использование инструментов и планирование задач;
— деплой и масштабирование своих ИИ-решений;
— работа с векторными хранилищами данных.
Занять место
Экосистема
.NET активно интегрирует ИИ (например, через Semantic Kernel). Наш курс поможет вам понять фундаментальные принципы построения автономных систем.Начинаем сегодня в 19:00 МСК.
Основные темы:
— путь от базовых промптов до мультиагентных систем;
— использование инструментов и планирование задач;
— деплой и масштабирование своих ИИ-решений;
— работа с векторными хранилищами данных.
Занять место
😁7
🛠 PostgreSQL как Dead Letter Queue
История о том, как в Wayfair отказались от Kafka DLQ в пользу PostgreSQL и получили более управляемую систему обработки сбоев.
Проблема: события падают, а видимости нет
Сбои встречались везде: API для обогащения данных падали или тормозили, консьюмеры крашились посреди обработки, события приходили с битыми или отсутствующими полями. Всё это находилось вне прямого контроля команды, но требовало изящной обработки.
Первая попытка: Kafka как DLQ
Логичным решением было использовать сам Kafka в качестве Dead Letter Queue. Общий паттерн: если событие не обработалось, отправляем его в отдельный топик DLQ.
Но быстро стало ясно, что это не лучший вариант. Kafka отлично двигает данные, но когда сообщения попадают в DLQ-топик, с ними сложно работать:
• Нельзя просто взять и выполнить запрос «покажи всё, что упало вчера»
• Нет нормальной фильтрации по причине сбоя
• Чтобы повторить обработку конкретного набора событий, нужны кастомные консьюмеры
• Для любого анализа требуется дополнительный инструментарий
Для системы, генерирующей критичные бизнес-отчёты, такое отсутствие видимости стало серьёзной проблемой.
Решение: PostgreSQL как первоклассный DLQ
Вместо публикации сбойных событий в топик Kafka, начали сохранять их прямо в таблицу DLQ в PostgreSQL. CloudSQL уже использовался как основное хранилище, так что операционно это почти ничего не добавило. Концептуально же сбои стали первоклассными гражданами системы, а не непрозрачными сообщениями, потерянными в потоке.
Дизайн-решения
• payload как JSONB — сохраняет сырое событие без жёсткой схемы. Можно хранить любую структуру и при этом эффективно запрашивать.
• Простая модель состояний — только PENDING и SUCCEEDED. Минимализм делает жизненный цикл события понятным.
• retry_after — предотвращает агрессивные повторы, когда зависимые системы нестабильны.
• retry_count — позволяет ограничивать количество попыток без внешнего состояния. Если событие не обработалось за 240 попыток — возможно, с ним что-то фундаментально не так.
• Временные метки — делают аудит и операционный анализ простым делом.
Целью не было заменить Kafka на PostgreSQL. Kafka остался основой для высокопроизводительного приёма событий, а PostgreSQL взял на себя то, что умеет лучше всего — долговременность, запросы и наблюдаемость вокруг сбоев.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#il_люминатор
История о том, как в Wayfair отказались от Kafka DLQ в пользу PostgreSQL и получили более управляемую систему обработки сбоев.
Проблема: события падают, а видимости нет
Сбои встречались везде: API для обогащения данных падали или тормозили, консьюмеры крашились посреди обработки, события приходили с битыми или отсутствующими полями. Всё это находилось вне прямого контроля команды, но требовало изящной обработки.
Первая попытка: Kafka как DLQ
Логичным решением было использовать сам Kafka в качестве Dead Letter Queue. Общий паттерн: если событие не обработалось, отправляем его в отдельный топик DLQ.
Но быстро стало ясно, что это не лучший вариант. Kafka отлично двигает данные, но когда сообщения попадают в DLQ-топик, с ними сложно работать:
• Нельзя просто взять и выполнить запрос «покажи всё, что упало вчера»
• Нет нормальной фильтрации по причине сбоя
• Чтобы повторить обработку конкретного набора событий, нужны кастомные консьюмеры
• Для любого анализа требуется дополнительный инструментарий
Для системы, генерирующей критичные бизнес-отчёты, такое отсутствие видимости стало серьёзной проблемой.
Решение: PostgreSQL как первоклассный DLQ
Вместо публикации сбойных событий в топик Kafka, начали сохранять их прямо в таблицу DLQ в PostgreSQL. CloudSQL уже использовался как основное хранилище, так что операционно это почти ничего не добавило. Концептуально же сбои стали первоклассными гражданами системы, а не непрозрачными сообщениями, потерянными в потоке.
Дизайн-решения
• payload как JSONB — сохраняет сырое событие без жёсткой схемы. Можно хранить любую структуру и при этом эффективно запрашивать.
• Простая модель состояний — только PENDING и SUCCEEDED. Минимализм делает жизненный цикл события понятным.
• retry_after — предотвращает агрессивные повторы, когда зависимые системы нестабильны.
• retry_count — позволяет ограничивать количество попыток без внешнего состояния. Если событие не обработалось за 240 попыток — возможно, с ним что-то фундаментально не так.
• Временные метки — делают аудит и операционный анализ простым делом.
Целью не было заменить Kafka на PostgreSQL. Kafka остался основой для высокопроизводительного приёма событий, а PostgreSQL взял на себя то, что умеет лучше всего — долговременность, запросы и наблюдаемость вокруг сбоев.
📍 Навигация: Вакансии • Задачи • Собесы
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍3🤔3
Работа с железом через .NET — это не просто про серверы и веб-приложения. С библиотекой Gpio вы можете управлять физическими устройствами напрямую с Raspberry Pi или других одноплатников.
Рассмотрим базовый пример: как заставить мигать светодиод.
Что понадобится
Минимальный набор компонентов: Raspberry Pi (или аналог с поддержкой .NET), светодиод на 5 мм, резистор 330 Ом, макетная плата и провода.
Как это работает
Схема собирается просто: плата подключается к аноду светодиода (длинная ножка), катод идёт через резистор на землю. Резистор ограничивает ток и защищает светодиод от выгорания.
В коде всего несколько строк:
using var controller = new GpioController();
controller.OpenPin(18, PinMode.Output);
bool ledOn = true;
while (true)
{
controller.Write(18, ledOn ? PinValue.High : PinValue.Low);
Thread.Sleep(1000);
ledOn = !ledOn;
}
В цикле мы записываем значение «включено» или «выключено», меняем состояние каждую секунду.
Приложение компилируется как self-contained и разворачивается на устройстве. После назначения прав на выполнение (
chmod +x) запускаете исполняемый файл — и светодиод начинает мигать с интервалом в секунду.📍 Навигация: Вакансии • Задачи • Собесы
#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍22❤🔥4🤔4❤1😁1
🐳 Docker для быстрого запуска сервисов локально
Docker это платформа для запуска приложений в контейнерах. Контейнер получает собственные зависимости, сетевую конфигурацию и порты и при этом не вмешивается в окружение хоста.
Предположим, вам нужно быстро поднять MongoDB локально, не устанавливая ее системным пакетом.
Достаточно выполнить:
Эта команда скачает официальный образ mongo с Docker Hub и запустит контейнер. Флаг
Так вы получаете рабочую MongoDB без отдельной установки сервера, настройки сервисов и борьбы с конфликтами версий.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#sharp_view
Docker это платформа для запуска приложений в контейнерах. Контейнер получает собственные зависимости, сетевую конфигурацию и порты и при этом не вмешивается в окружение хоста.
Предположим, вам нужно быстро поднять MongoDB локально, не устанавливая ее системным пакетом.
Достаточно выполнить:
docker run -p 27017:27017 mongo
Эта команда скачает официальный образ mongo с Docker Hub и запустит контейнер. Флаг
-p 27017:27017 пробрасывает порт на хост, то есть вы обращаетесь к базе на localhost:27017.Так вы получаете рабочую MongoDB без отдельной установки сервера, настройки сервисов и борьбы с конфликтами версий.
📍 Навигация: Вакансии • Задачи • Собесы
#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
💯15🥱3👍1👏1
🛋 Работа в кайф
Продуктивность — это не про силу воли и мотивацию. Это про то, как вы обустроили своё рабочее место. Синий свет экрана, температура в комнате, даже то, сколько воды вы выпили за день — всё это напрямую влияет на работу вашего мозга.
➡️ В статье 10 базовых советов по обустройству вашего рабочего места
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
Продуктивность — это не про силу воли и мотивацию. Это про то, как вы обустроили своё рабочее место. Синий свет экрана, температура в комнате, даже то, сколько воды вы выпили за день — всё это напрямую влияет на работу вашего мозга.
📍 Навигация: Вакансии • Задачи • Собесы
Please open Telegram to view this post
VIEW IN TELEGRAM
💯7
C#/.NET-разработчик — до 300 000 ₽ и удалёнка.
С# разработчик — от 200 000 ₽ и снова удалёнка.
.NET Developer — внезапный офис в Новосибирске.
📍 Навигация: Вакансии • Задачи • Собесы
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4❤2
AI-агенты в экосистеме .NET: расширяем границы возможного
Интеграция ИИ в энтерпрайз-продукты требует понимания того, как работают автономные системы. Изучите общие принципы построения агентских систем, чтобы внедрять их в свои проекты.
Курс «Углубленные AI-агенты» даст вам глубокую экспертизу в актуальном стеке.
На обучении вас ждёт:
— проектирование автономных агентских систем;
— освоение
— интеграция RAG и инструментов планирования;
— 13 живых вебинаров и поддержка менторов.
Поток уже стартовал, присоединяйтесь сейчас.
🚀 Записаться на основной курс
Если сомневаетесь — просто посмотрите вводное занятие.
Интеграция ИИ в энтерпрайз-продукты требует понимания того, как работают автономные системы. Изучите общие принципы построения агентских систем, чтобы внедрять их в свои проекты.
Курс «Углубленные AI-агенты» даст вам глубокую экспертизу в актуальном стеке.
На обучении вас ждёт:
— проектирование автономных агентских систем;
— освоение
LangGraph, CrewAI и AutoGen;— интеграция RAG и инструментов планирования;
— 13 живых вебинаров и поддержка менторов.
Поток уже стартовал, присоединяйтесь сейчас.
🚀 Записаться на основной курс
Если сомневаетесь — просто посмотрите вводное занятие.
❤🔥2❤1😁1
ExecuteUpdate и ExecuteDelete появились для случаев, когда вам не нужны сущности и сложные хуки.
Это способ выполнять быстрые массовые операции, говоря с базой на языке SQL через LINQ.
Простой пример с заказами, которые нужно отметить как просроченные:
public async Task<IActionResult> ExpireOldOrders()
{
var cutoff = DateTime.UtcNow.AddDays(-30);
var affectedRows = await _db.Orders
.Where(o => o.Status == OrderStatus.Pending
&& o.CreatedAt < cutoff)
.ExecuteUpdateAsync(setters =>
setters.SetProperty(
o => o.Status,
OrderStatus.Expired));
return Ok(new { affectedRows });
}
EF Core сгенерирует один SQL примерно такого вида:
UPDATE Orders
SET Status = 2
WHERE Status = 0
AND CreatedAt < @cutoff
Приложение отправляет в базу одну команду, а не тысячи мелких запросов. С точки зрения БД — это максимально естественный сценарий: нагрузка на сеть и блокировки минимальны.
ExecuteDelete решает такую же задачу для удаления:
public async Task<int> CleanOldLogsAsync(DateTime cutoff)
{
var affected = await _db.Logs
.Where(l => l.CreatedAt < cutoff)
.ExecuteDeleteAsync();
return affected;
}
EF Core не загружает логи в память — удаление происходит одним SQL-запросом.
Важно: эти методы обходят change tracking и не вызывают события SaveChanges.
Используйте их, когда производительность важнее бизнес-логики в коде.
📍 Навигация: Вакансии • Задачи • Собесы
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15❤1
Feature Flags — это условные переключатели, которые позволяют включать/выключать фичи на лету, без передеплоя приложения.
Зачем они нужны
• Безопасный rollout — можно включить фичу для 10% пользователей, проверить метрики, затем раскатывать дальше.
• A/B тестирование — запуск двух версий фичи и выбор лучшей на основе данных.
• Eсли что-то пошло не так, флаг выключается за секунду вместо отката всего деплоя.
• Возможность коммитить незавершённый код без риска для продакшна
Подготовка:
// Добавим NuGet пакет
dotnet add package Microsoft.FeatureManagement
// В appsettings.json
"FeatureManagement": {
"NewDashboard": false
}
В коде:
if (await featureManager.IsEnabledAsync("NewDashboard"))
{
RenderNewDashboard();
}
else
{
RenderOldDashboard();
}
📍 Навигация: Вакансии • Задачи • Собесы
#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤4
ValueTask часто хвалят за экономию памяти. Но если использовать его в публичном API, потребители могут не оценить такой шаг.
Вопрос: чем так плох ValueTask в публичном API? Он же снизит аллокации
Ответ:
📍 Навигация: Вакансии • Задачи • Собесы
#dotnet_challenge
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3😢1
🎯 Нестандартные форматы резюме
Листайте карточки и подбирайте вариант резюме под свои навыки. В комментах можете поделиться своими проектами 👇
➡️ В статье ещё два формата
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
Листайте карточки и подбирайте вариант резюме под свои навыки. В комментах можете поделиться своими проектами 👇
📍 Навигация: Вакансии • Задачи • Собесы
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
😁7👍5🤔2
LangGraph vs Semantic Kernel: архитектура агентов
В .NET мире популярен Semantic Kernel, но индустрия движется к графовым подходам.
Архитектурные преимущества:
— цикличность: нативная поддержка циклов (ReAct pattern);
— state management: управление контекстом похоже на работу с сессиями;
— human-in-the-loop: возможность поставить граф на паузу, получить апрув человека и продолжить.
Курс по архитектуре уже стартовал.
Записаться на курс
Смотреть первую лекцию бесплатно
В .NET мире популярен Semantic Kernel, но индустрия движется к графовым подходам.
LangGraph реализует паттерн, где агент — это не просто цепочка плагинов, а граф с состоянием.Архитектурные преимущества:
— цикличность: нативная поддержка циклов (ReAct pattern);
— state management: управление контекстом похоже на работу с сессиями;
— human-in-the-loop: возможность поставить граф на паузу, получить апрув человека и продолжить.
Курс по архитектуре уже стартовал.
Записаться на курс
Смотреть первую лекцию бесплатно
👍6❤1
В .NET для HTTP-запросов фабрика
IHttpClientFactory упрощает создание клиентов, интегрируется с DI и решает проблемы вроде утечек сокетов.Фабрика кэширует обработчики сообщений, управляет их временем жизни и добавляет логирование.
Зачем нужна фабрика
HttpClient из Framework 4.5 часто создают вручную, но это приводит к проблемам: сокеты не освобождаются, DNS не обновляется. Фабрика решает это через пул обработчиков с лайфтаймом в 2 минуты по умолчанию.
Она регистрируется через
AddHttpClient в IServiceCollection и дает доступ к CreateClient. Короткоживущие клиенты подходят для большинства случаев, в отличие от долгоживущих с PooledConnectionLifetime.Предупреждение: если нужны куки, лучше обойтись без фабрики из-за шаринга
CookieContainer.Способы использования
Разработчики выбирают между базовым, именованными, типизированными клиентами или сгенерированными через Refit.
В базовом варианте инжектят
IHttpClientFactory и вызывают CreateClient для каждого запроса. Это просто для рефакторинга старого кода.Именованные клиенты настраивают по имени из конфига, с базовым URI и заголовками вроде User-Agent:
builder.Services.AddHttpClient("MyClient", client =>
{
client.BaseAddress = new Uri("https://api.example.com/");
client.DefaultRequestHeaders.UserAgent.ParseAdd("MyApp");
});Затем
CreateClient("MyClient").Типизированные удобны для конкретного API: класс принимает
HttpClient в конструкторе, фабрика регистрирует его через AddHttpClient<T>.Логика запросов инкапсулируется в методах класса, DI все подхватывает. IntelliSense работает, нет строковых ключей.
Не используйте в синглтонах: клиент должен быть короткоживущим, иначе DNS не обновится. Лучше именованные или SocketsHttpHandler:
public class ApiService(HttpClient client)
{
public async Task<Todo[]> GetTodos(int id) =>
await client.GetFromJsonAsync<Todo[]>($"todos/{id}");
}
В итоге фабрика делает HTTP-клиенты в .NET предсказуемыми и масштабируемыми. Для прода это как стандарт: меньше багов с соединениями, проще DI.
📍 Навигация: Вакансии • Задачи • Собесы
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6
🧑💻 Неявная проверка на null
В C# можно заставить любой класс вести себя в if как в JavaScript: просто if (myObject) и внутри проверка на null. Это работает благодаря перегрузке операторов.
Создайте класс с двумя статическими методами:
Теперь
Единственный минус: никто не ожидает такого, код становится загадкой для команды. Лучше стандартные
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#sharp_view
В C# можно заставить любой класс вести себя в if как в JavaScript: просто if (myObject) и внутри проверка на null. Это работает благодаря перегрузке операторов.
Создайте класс с двумя статическими методами:
public class User
{
public string Name { get; set; }
public static bool operator true(User? user) => user?.Name != null;
public static bool operator false(User? user) => user?.Name == null;
}
Теперь
if (user) сработает если имя задано, иначе попадет в else. Компилятор автоматически вызывает нужный оператор при булевом контексте.Единственный минус: никто не ожидает такого, код становится загадкой для команды. Лучше стандартные
is not null или !ReferenceEquals(null, obj).📍 Навигация: Вакансии • Задачи • Собесы
#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15😢12😁6🌚2
Класс
Random в .NET генерирует псевдослучайные числа для игр, тестов или симуляций. Он работает на основе сида, обычно времени, и дает целые, дробные значения или байты.Основы класса Random
System.Random создает последовательности чисел через алгоритм. Для простого инта берут Next(min, max), где верхняя граница не включается.Переиспользуйте один экземпляр, иначе в цикле из-за одинаковых сидов выйдут повторения. Статический или инжектированный через DI вариант подходит для прода:
var rng = new Random();
int число = rng.Next(1, 101); // от 1 до 100
NextDouble возвращает от 0.0 до 1.0, умножьте и сдвиньте для нужного интервала. Байты через NextBytes заполняют массив. Это для тестовых файлов или симуляций.double температура = rng.NextDouble() * 50 - 10; // от -10 до 40
byte[] буфер = new byte[16];
rng.NextBytes(буфер);
Обычный
Random не годится для токенов или паролей, предсказуем при известном сиде. Берите RandomNumberGenerator из System.Security.Cryptography для криптографии.GetInt32(1, 101) или Fill для байт. В API для ключей всегда крипто-вариант.Random не потокобезопасен, общий экземпляр сломается. ThreadLocal<Random> создаст по инстансу на поток. Parallel.For с ним работает корректно, без гонок:var локальныйRng = new ThreadLocal<Random>(() => new Random());
Parallel.For(0, 100, i => {
int значение = локальныйRng.Value!.Next(100);
});
📍 Навигация: Вакансии • Задачи • Собесы
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13❤5