C# Short Posts 🔞 – Telegram
C# Short Posts 🔞
251 subscribers
110 photos
4 videos
151 links
Здесь я, Дима Афонченко @Undermove1, публикую короткие заметки о разработке (и около). Я не претендую на правильность высказываний и открыт к дискуссиям, исправлениям и конструктивной критике. С любыми деструктивными вещами можно приходить в комменты)
Download Telegram
Воркшоп: Сделай своего Claude! 🌧

Недавно в Github trending наткнулся на репозиторий-воркшоп по созданию своего агента how-to-build-coding-agent. На удивление ни в каких больше AI каналах про него инфы нет, а репозиторий – топовый!

Мне в нем нравится структура:

1. Basic Chat — talk to Claude
2. File Reader — read code files
3. File Explorer — list files in folders
4. Command Runner — run shell commands
5. File Editor — modify files
6. Code Search — search your codebase with patterns

То есть начаинем с того, что мы вообще можем через консольку общаться с моделькой, затем наклеиваем на него возможность читать файлы, потом навешиваем умение пробегаться по папкам, и так далее. В общем, каждый шаг идеально маленький, чтобы не бояться его сделать, и достаточно полезный, чтобы была мотивация его сделать.

Думаю, что после дотнекста возьмусь его пройти, ибо давно хотелось попробовать смастерить своего агента и потестить его на своем репозитории.

Единственное, что он весь на go, но я перевайбкодю его на шарпик, разумеется
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍33🔥2
Потестировал Qcoder и Junie

Прогнал еще двух агентов на своем тесте. На это раз смотрел китайский Qcoder, который предложили в комментариях и долгожданный Junie от Jetbrains

🟢️️️️️️ Qcoder
Cправился довольно неплохо. Это тоже отдельный редактор типа курсора, НО мне понравилось, что заодно устанавливается консольная приложуха. То есть, если не хотите кодить в отдельной прилке – не проблема просто открываете терминал внутри любимой IDE и пользуетесь. Это довольно удобно!

🧞 Junie
А вот он разочаровал. Версия промпта с тестами выглядела чуть поживее и ближе к делу, но тоже не собралась — не скомпилировалась.

В целом — сыровато. Верю, что допилят, но, честно, от тулзы, которую хвалили как «лучший вариант для C#» за счёт интеграции со структурой языка, я ждал большего на старте.

Из хорошего: можно подключить локальную модель. Это круто. Когда у компании есть бизнес помимо одной тулзы «на коленке», они могут позволить юзерам юзать и локалку без страха, что кто-то случайно недоплатит за токены.

Так что будем ждать, а пока ну ка его нахуй этот Junie. А Qcoder топ. Думаю, буду пробовать на пет проектах консольную версию этого дела.

Итого таблица соревнований агентов сейчас выглядит так как на пояснительном дикпике 🍆
3👍2🔥2
Вот кстати периодически тоже наблюдаю, что агенты тупеют. Интересно, с чем это может быть связано. Может это просто иллюзия восприятия? Или я просто промпты периодически хуже пишу. Или они там пытаются экономить и втихую подсовывают более мелкие модельки?
💯2👾1
Forwarded from EDU (Bayram Annakov)
Codex бьет Claude Code

В пятницу в очередной раз уперся в рейт лимиты Claude Code, не выдержал и решил расчехлить Codex CLI и дать ему второй шанс - и очень приятно удивился! С тех пор не притрагивался к CC, а вы знаете, насколько я в восторге был от него.

Что определило мое решение и отличный experience:
1) В последние недели Claude Code то ли потупел (я сижу постоянно на opus модели), то ли что-то ребята подкрутили на серваке, но он по кругу водил меня с одними и теми же ситуациями, и зачастую мне ничего не оставалось как самому сесть и разобраться в том, что происходит, и поправить руками. Особенно часто это было во время очередного рейт лимита :)

2) Кстати, очень быстро стали наступать рейт лимиты: обычно я выбирал их за 2 из 3х часов, на прошлой неделе же это было в первые 30 мин

3) Быстро стал расходоваться контекст, постоянно приходилось очищать, компактить, писать в файл. Проверил свой claude.md, но он не сказать, что был такой большой

4) Когда же пересел на Codex, то исправил проблему, контекст прямо радует, рейт лимитов пока не испытал, и меня радует его краткость, явно менее выраженное подхалимство, и проактивность (концовки вида "а хочешь я еще сделаю вот это вот?" - см. картинку в аттаче)

В общем, не знаю, как долго продлится этот праздник, но рекомендую попробовать. В Codex пока не хватате привычных фичей из CC - субагенты, возможность продолжить разговор, planning mode и тп, но судя по change log-у они быстро нагоняют)

P.S. Да здравствует конкуренция!
2👍1😎1
Вчера переводил пет-проект на GlobalUsings.cs

Это если помните такая фича, которая позволяет прописать


using System;


в одном файле и больше нигде не прописывать эту преамбулу.

Ну и туда еще можно напихать часто используемые юзинги. Вот только встает вопрос, а какие считать часто используемыми?

Навайбкодил для мака вот такой скриптос, который позволяет посчитать самые частые юзинги


find /your/repos/path/src -name "*.cs" | xargs grep -h "^using " | sort | uniq -c | sort -nr | head -50


Получился вот такой топ:


432 using System;
187 using System.Threading.Tasks;
165 using System.Threading;
157 using System.Collections.Generic;


Все это пихнул в файлик GlobalUsings.cs – profit! 💰

🅰️ Так что если у вас было желание использовать GlobalUsings.cs но вы как и я мучались с вопросм, а что можно туда запихнуть, то может этот скриптос вам поможет.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥72💋22🙏1
Ну что же. Не говори гоп пока не перепрыгнешь. Я наконец перепрыгнул и выступил на DotNext! Так что ГОП!

Чуть позже соберусь и расскажу в подробностях, как придумал тему, как готовился, как обгонял, как подрезал и так далее.

А пока что могу выдохнуть, потому что это был марафон. Думаю, что на подготовку ушло не менее 100 часов. Это по самым скромным оценкам.

В конце перед самым докладом ориентировался в рассказе настолько свободно, что мог без слайдов по памяти рассказать с любой минуты. То есть называете число с 0 до 60 и я с колес начинаю воспроизводить.

Как я понял это довольно высокая степень упоротости и не все так мощно все это прогоняли. Но мне было по кайфу. Очень хотелось рассказать про кубер простым языком.

Через год докладик опубликуют и я им тут поделюсь с удовольствием)

Ну а пока что:

❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️
Спасибо всем, кто смотрел, поддерживал, задавал вопросы и написал после доклада приятные слова! Это правда очень сильно помогает, и сильно снижает стресс после такой жесткой нагрузки

И спасибо Антону Оникийчуку за оргомную помощь в подготовке доклада! Благодаря этой помощи я сильно углубил знания во всем в чем только можно касаемо работы сети в кубере!
❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥19❤‍🔥651
😎 Топ 10 вещей которые чувак с NDC делает в каждом проекте. И мой топ 5 из его топ 10

Сгонял тут недавно в отпуск в Испанию, где много гулял и смотрел на всякие старые здания и прочие красоты. В последнее время чтобы что-то узнать о том или ином месте я просто пишу в ChatGPT что нахожусь там-то и там-то и мол расскажи мне про то что я вижу перед собой.

Захотелось это автоматизировать, поэтому в перерывах между прогулками я пытался навайбкодить себе бота-экскурсовода, который делает простую фишку – ты ему кидаешь свою локацию, а он тебе рассказывает, что ты на ней можешь увидеть. И все это в стиле эксцентричного экскурсовода.

Как оказалось, я в первый раз вайбкодил что-то с нуля. 🐸 И для меня особой неожиданностью стало, что агент, который на готовом проекте пишет норм код, на новом проекте разводит грязь даже в readme файле.

Но, к счастью, мне попался вот такой доклад с NDC где челик рассказывает про то, какие 10 вещей он делает в каждом проекте, чтобы все было чистенько:

Из мастхевов, которые я сам стараюсь делать было вот такое:

1️⃣ TreatWarningsAsErrors – если честно настолько полезная фича, что я думал, что она уже везде по умолчанию включена.

2️⃣ Не прокидывать IOptions, а передавать конфиг в виде объекта который уже достал все значения из Value

3️⃣ Так называемая практика Early returns. Которая по сути предлагает не использовать по возможности блок else чтобы не увеличивать количество скобочек и визуальную сложность метода. Я кстати эту практику считал вкусовщиной, но посмотрев на код, который игнорирует эту практику, я понял, что все же это масхэв)))

4️⃣ Validate on Build. Вот это тоже хорошее дело. Позволяет автоматом проверить DI, и что вы не запихнули случайно Scoped сервис в Singleton. Для агентов это особенно важно, потому что их цикл разработки строится на обратной связи от ошибок билда

5️⃣ Central Package Management. Тоже мастхэв и вообще одна из самых полезных фич в шарпе. Без него сейчас нет смысла вообще стартовать проект. Как и без slnx

Остальные пункты тоже ничего, но вот эти пять мне показались самыми важными

Ну и еще одна вещь которая меня удивила ServerHeader: Kestrel. Честно говоря не знал ни зачем это заголовок, ни что он вообще существует. А он есть! Оказалось, что хитрые аналитики хотели так посчитать сколько людей юзают ASP NET. Но с точки зрения безопасности давать хакерам такую подсказку все же не стоит. Так что хэдеры эти нужно удалять ручками


builder.WebHost.UseKestrel(options => options.AddServerHeader = false)


На основе этого доклада накидал промпт для агента, чтобы он сразу писал более менее чисто. Сам промпт в комментах. Еще и неплохой чек-лист для самого себя получился))
Please open Telegram to view this post
VIEW IN TELEGRAM
6❤‍🔥43🔥2
Потестил новый браузер от OpenAI – Atlas

Попросил заказать пару штук (электрическая молотилка для кофе и холдер для ноута) на TEMU (что-то типа алиэкспресса) и найти хорошие по соотношению цена/отзывы и поискать скидочные купоны.

В целом он смог норм собрать корзину. Думаю, это сэкономило мне несколько часов на том, что я не залипал во все подряд. Думаю, вы понимаете о чем я ☺️

Забавно, что когда он пытался найти купоны, у него это явно не получилось и он начал тупо брутфорсить разные комбинации 🐈

Но, в общем, удобно. Не скажу, что я бы юзал как основной браузер, но для вот такой штуки типа покупок на маркеплейсах, организации поездок и т.п., мне кажется очень даже ничего.

Не революция, но и не совсем бессмысленная штука. Я заметил, что все чёт разочаровались в нем, но думаю, что дело в завышенных ожиданиях. У меня ожиданий не было, так что пока ставлю 7 из 10 и, думаю, что точно заслуживает внимания.

PS: Я вот еще думаю, что эту штуку будет удобно использовать чтобы с какой-то спарсить данные и превратить в таблицу или гуглодок. И в целом для работы с гуглодоками. Особенно с учетом, что эта штуковина может заходить под вашим аккаунтом куда-то где нужен доступ.
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍2💯2
👨 Для чего нам Distroless?

Distroless образы довольно давно уже вошли в обиход. И у нас в Додо вообще есть требование, что все наши сервисы должны работать на них. Но я всё ещё в разговорах замечаю, что большинство вообще не сечёт, о чём это и для чего.

Оно в целом не удивительно: это довольно неочевидно с одной стороны и довольно очевидно с другой. Поэтому с одной стороны не задают вопросов, а с другой — не видят смысла в ответах.

Чтобы полностью проникнуться всей сутью, нужно знать довольно много о докере и о контейнерах, но главную суть, которую нужно понимать, — следующее:

Контейнер — это просто процесс, запущенный с определёнными ограничениями. То есть это не виртуалка.

Любому процессу нужно давать как можно меньше прав, и все это прекрасно знают. Но почему?

Ведь я сам написал весь код, если даже не я написал этот код, то я проведу ревью, и, если в коде есть какие-то подозрительные места, то я их уничтожу!

Так думает обыватель, и он по-своему прав в этой невинной наивности.

Но есть такая штука, как нугет-пакеты, и хуже того — есть нугет-пакеты, которые используются в нугет-пакетах.

И весь код, который там написан, как вы понимаете, поревьюить, мягко говоря, не получится.

Не использовать нугет-пакеты — это первый шаг к тому, чтобы уединиться в лесу и тихо там умереть в шапочке из фольги.

😡 Ок, но какую опасность может представлять вредоносный нугет-пакет?

Да — очень простую. К примеру, в одной из транзитивных NuGet-зависимостей появилась строка, которая при инициализации вызывает запуск внешней программы через Process.Start. Если в контейнере есть утилиты (bash, sh, curl, wget), то вредоносный код может просто запустить их и отправить конфиденциальные данные (переменные окружения, файлы конфигурации, нюдсы, дикпики) на внешний сервер или вызвать внутренний админ-эндпоинт под именем сервиса.

🅰️ как нам поможет distroless?

А так, что в distroless-образе этих внешних утилит просто нет — нет bash, нет curl, нет sh и даже нюдсов и дикпиков нет. Поэтому сценарий «внезапно запустить системную утилиту из контейнера» потерпит поражение: бинарник не найден, команда не выполнится. Это закрывает быстрый и «грубый» вектор дополнительной загрузки кода, который часто используется в мелких эксплойтах и supply-chain-атаках.

Очевидно, что это не стопроцентная защита. Если вредоносный код использует возможности самого рантайма (в .NET — HttpClient, файловые операции и т.д.), он по-прежнему сможет делать сетевые запросы или читать файлы. Distroless снижает эти конкретные риски. Вот, собственно, и всё.

Поделитесь по-сестрински этим знанием с теми, кто ещё не в курсе. Рили почему-то мало людей понимают про это.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥433
🎃 Воскрешаем мертвые репозитории! ☠️

Я тут подумал, ведь бывает так, что призраками становятся не только люди, но и репозитории! К примеру вы хреначили репозиторий, который набрал пару тысяч звезд, а потом… Ну просто забили. И репозиторий как бы жив и популярен, но никому уже не нужен. Получается застрял между двух состояний. Выходит – призракопозиторий 👻

Короче, за вечер с браузером атлас навайбкодил слот-машину, которая позволяет почтить память почивших репозиториев.

Идея простая:
1. Заходите на сайт
2. Крутите слот-машину 🎰 (тянем рычаг справа вниз)
3. Вам выпадает три рандомных репозитория с большим количеством звезд, но с последним коммитом, сделанным Бог знает когда
4. Ставите репозиторию звезду
5. Автор охреневает и радуется!

Если вы давно читаете мой канальчик, но то вы точно знаете, как я люблю пропагандировать поставку звезд на репозитории. Так что эта механика идеально ложится в мой вайб и в сегодняшнюю тематику)

Можно даже язык программирования профильтровать. Я пока вчера залипал в свое собственное казино, нашел много прикольных реп, с классными фичами для юньки. Короче, попробуйте! Даже если звезду не вьебете, то все равно инетерсно посмотреть, что было популярно и померло лет эдак пять назад.

Ну и моей репке тоже звездочку там аккуратно звезданите ⭐️. Может через лет пять круг замкнется и она высветит в слотах сама себя) Лайк и репост тоже приветствуются, разумеется 🎃
Please open Telegram to view this post
VIEW IN TELEGRAM
8🎃5💘4
Вчерашний хэллоуин обернулся настоящим кошмаром — сегодня рабочая суббота!
💯8😡33😱2
Пиздос как это круто! Вообще у нас супер-крутая команда работает над авторизацией. Регулярно что-то поставляют такое, чего нам людям даже и не снилось – атакующие корабли, пылающие над Орионом, лучи Си разрывающие мрак у ворот Тангейзера. Все эти моменты теперь дополнены и такой вот автозизованной библиотекой
83😎2
Forwarded from Dodo Engineering
🐳 Нашу реализацию Passkey для .NET признал FiDO Alliance

Они разрабатывают и продвигают открытые стандарты для безопасной аутентификации без паролей по всему миру. Более того, FIDO Alliance включил наш способ в список библиотек, рекомендованных к использованию.

Почему это круто?

Passkey безопаснее и удобнее паролей. Не надо ничего запоминать, можно использовать биометрию.
Мы разработали собственное высококачественное решение для авторизации с помощью Passkey, подходящее именно нам. Когда мы искали подобные решения на рынке, то нашли всего два: одно — очень дорогое, а другое — технологически устаревшее.
Наше решение признали на международном уровне и теперь рекомендуют для использования в других компаниях.

Чем занимается FIDO?

Fast IDentity Online Alliance устраняет зависимость от уязвимых к фишингу, перехвату и утечкам паролей. Они стремятся:
🟠повысить безопасность онлайн-аутентификации;
🟠сделать вход в аккаунты удобнее — с помощью отпечатков пальцев, Face ID, USB-ключей и не только;
🟠найти и предложить открытые стандарты авторизации для всех — компаний, разработчиков, производителей устройств.

👑 Кто входит в альянс?

В FIDO Alliance входят: Apple, Google, Microsoft, Amazon, Intel, Samsung, Mastercard, VISA, Bank of America и другие крупные компании.

🌐 Где используются FIDO-стандарты?

🟠В системах двухфакторной аутентификации. Например, при логине в Google с использованием ключей безопасности.
🟠В корпоративных сервисах и VPN.
🟠В банковских и других финтех-приложениях.
🟠В операционных системах: Windows Hello, Apple Face ID/Touch ID через Safari, Android Biometrics и т. д.

💻 И где теперь это будет использоваться?

Во-первых, мы сами использовали нашу библиотеку, чтобы подключить к Dodo IS Passkey.

Во-вторых, наша библиотека — OpenSource. Ее могут использовать все, кому нужно, и везде, где есть вход по логину/паролю, а бэкенд написан на .Net. Сейчас есть 9 форков — это немного, но уже значит, что кто-то сделал себе копию и доработал ее под себя.
Please open Telegram to view this post
VIEW IN TELEGRAM
👏76
Сегодня – .NET Conf и, конечно, день релиза .NET 10

На самом деле, в этом году я впервые ждал новую версию .NET по двум причинам:

🥇 Запускаемые файлы C# — для меня эта фича самая ожидаемая. Шарпику уже давно было пора сделать что-то со своей инфраструктурой. Я с огромной завистью смотрел на то, как быстро запускается всё питоновское и нодовское на компе. Как удобно вообще можно запускать любую утилиту просто из консоли — и прям дико завидовал. Большая часть изменений в .NET до этого, на мой взгляд, — ну не хуйня, но близко к этому. Каждый раз, когда говорили про то, что упростят написание очередного свитч-кейса тем, что дадут писать палочку вместо слова, рука сама небрежно касалась лица, производя шлепок.

🥈 И вторая причина, по которой жду .NET 10, — это просто LTS-версия. До недавнего времени не видел смысла переходить на STS-версии, ибо при таком манёвре ты фактически обрекал себя на переезд строго через год. А это обычно в ноябре, под Новый год, когда сроки горят. То есть окно манёвра было мизерное. А я, к примеру, предпочитаю перестраховаться и взять сразу то, что будет долго поддерживаться, чтобы переехать потом спокойно — под сезон отпусков, когда страсти поутихают.

Такие дела. Плюс, говорят, там ускорили что-то, что-то там на стек перенесли. Но это уже перестало удивлять — его, кажется, каждый год ускоряют в сто раз. Так что скоро новая версия дотнета уйдёт в нирвану и начнёт обрабатывать ещё не отправленные запросы.
🔥75😁41👍1👌1
❤️ Очень странные дела: баги в .NET 10

В пятницу классно поразгоняли с ребятами на наших внутренних техпосиделках про переезд на .NET 10.

Хедлайнером у нас был ослепительный @granstel, который перевёл свой сервис на .NET 10 первым (как минимум в Додо а может и в мире, кто знает). Сервис некритичный, но полезный — он является бэком для этой охуенной интерактивной карты. Идеальная площадка для тестов.

Так вот что удалось выяснить в процессе переезда/обсуждений:

1) В целом всё работает
2) Но есть один довольно критичный ишуй

В версии 10.0.100 внезапно сломан хендлинг вложенных try/catch/finally.
Как показано на пояснительном дикпике выше 🍆
Если внутренний finally бросает исключение, то:

внутренний catch не вызывается,

внутренний finally не доходит до конца,

внешний finally не вызывается вообще,

исключение вылетает наружу без обработки.

Довольно жёсткая штука — потому что using и await using разворачиваются компилятором именно во вложенные try/finally. А значит, при dispose может соскочить вся цепочка освобождения ресурсов.

То есть вложенный try/catch в принципе не перехватывает исключение из вложенного finally. А это уже влияет и на using, и на await using.

То есть вот такой код может быть потенциально опасным, если disposableTwo в своем диспоузе кинет исключение


using System;
using System.Threading.Tasks;

await using var disOne = new FirstDisposable("ONE");

await using var disTwo = new SecondDisposable("TWO");

Console.WriteLine("Before throw");
throw new Exception("FUCK");


sealed class FirstDisposable : IAsyncDisposable
{
private readonly string _name;
public FirstDisposable(string name) => _name = name;

public async ValueTask DisposeAsync()
{
Console.WriteLine($"DisposeAsync({_name}) START");
await Task.Delay(10);
Console.WriteLine($"DisposeAsync({_name}) END");

// На .NET 10.0.100 этот DisposeAsync вообще НЕ вызовется,
// потому что исключение из DisposeAsync(TWO) оборвёт цепочку.
Console.WriteLine($"NOTE: DisposeAsync({_name}) WAS CALLED — но это произойдёт только на .NET 8");
}
}

sealed class SecondDisposable : IAsyncDisposable
{
private readonly string _name;
public SecondDisposable(string name) => _name = name;

public ValueTask DisposeAsync()
{
Console.WriteLine($"DisposeAsync({_name}) THROWS — сейчас всё сломается");
throw new Exception($"DisposeAsync boom: {_name}");
}
}


Это утечки коннектов, файлов, сокетов, транзакций — что угодно.
Учитывая, что многие библиотеки используют IAsyncDisposable — в общем может стрельнут.

Все уже пофикшено судя по всему, наверняка заедет в следующую версию.

🚧 Вообще не всем дано переехать сразу.

Например, я попытался перевезти свою Базу знаний на новые рельсы, но столкнулся с тем, что нужный пакет Pomelo.EntityFrameworkCore.MySql пока отсутствует для .NET 10.

Так что переехать сходу смогут не все.
Может, даже и хорошо — с таким багом можно и потерпеть 🎃
Please open Telegram to view this post
VIEW IN TELEGRAM
5👾5🤝2
С этим красавчиком мы вместе делаем новую Базу Знаний для Додошки) Вообще классно работать с заряженными людьми!
4🤝1
Знакомьтесь, Blok!

Blok — это блочный, визуальный open-source редактор типа Notion.

В основу Blok лёг Editor.js — прекрасный визуальный редактор, который в своём развитии остановился где-то в 2018-м году, где было приемлемо иметь средненький UX, плохую документацию и решение не поддерживающее современные фреймворки.

Blok призван решить все эти проблемы и стать тем самым визуальным редактором, который вы искали.

Уже сейчас в Blok, в отличие от Editor.js, исправлены многие баги и проблемы безопасности, повышена стабильность и тестируемость редактора, а также появилась возможность перетаскивать блоки с помощью drag&drop!

В ближайших обновлениях Blok станет React-first для максимально удобной интеграции с вашими приложениями.

Blok доступен бесплатно прямо сейчас!
🔥4311
А вот результат, ради чего все это делается! Человек пару недель ночами не спал – делал возможным Notion-like экпириенс для наших редакторов! 🧨

На гифке короткое представление, как было и как стало:
This media is not supported in your browser
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤‍🔥104🔥2
Год назад делали с Серегой Орловым LiveActivities на андроиде.

Это такая штука, как на пояснительном дикпике выше. Выглядит просто.

Но я тогда открыл для себя, что в Андроиде все вещи, которые выглядят простыми скорее всего делать будет тупо сложно!

Короче, в своей статье Серега рассказывает как с помощью новой фичи LiveUpdates можно сделать такую вот штучку с прогресс-баром и как это пока что ограниченно в возможностях.

К примеру на верхней картинке верхний и нижний островок – это тупо разные компоненты, а не один и тот же просто переверстанный 👁👁

Вообще мне всегда было забавно, как у нас ребята на андроиде радуются таким вот штучкам. Мне всегда это было как-то до лампочки, у меня вообще все уведомления выключены. А у них там целая история в этих отключенных оповещениях!

Короче, статья вышла прикольная! Заслуживает плюсика в карму 💯
Please open Telegram to view this post
VIEW IN TELEGRAM
53👍1
🐸🐸 BackgroundTaskQueue

В первый раз за долгое время в практике понадобилось использовать бэкграундную таску.

Нужно было добавить в процесс логина автоприсваивание пользователям определенных доступов. Операция не обязательная и из-за нее не должен падать логин. Тем более процесс логина из-за нее тоже не хочется растягивать.

Можно было сделать fire and forget опустив слово await:


groupAccessService.AssignPredefinedSpacesAsync(existingUser, CancellationToken.None);


То есть пустить таску на самотек. С одной стороны просто и понятно, но хочется как-то понимать, дошла таска до своего финала или нет и как-то все это залогировать. Короче хочется больше контроля над таким.

Вспомнил, что когда-то с IHostedService слышал про BackgroundTaskQueue

Оказалось, что в доке прям есть кусок кода, который мне нужен. По нему решил реализовать вот такой простенький бэкграунд кью воркер


using System.Threading.Channels;

namespace Dodo.KnowledgeBase.Web.Services.BackgroundTasks;

public class BackgroundTaskQueue(IServiceScopeFactory serviceScopeFactory) : IBackgroundTaskQueue
{
private readonly Channel<Func<CancellationToken, ValueTask>> _queue =
Channel.CreateUnbounded<Func<CancellationToken, ValueTask>>();

public async ValueTask QueueAsync(Func<CancellationToken, ValueTask> workItem)
{
ArgumentNullException.ThrowIfNull(workItem);
await _queue.Writer.WriteAsync(workItem);
}

public async ValueTask QueueAsync(Func<IServiceProvider, CancellationToken, ValueTask> workItem)
{
ArgumentNullException.ThrowIfNull(workItem);

await _queue.Writer.WriteAsync(ScopedWorkItem);
return;

async ValueTask ScopedWorkItem(CancellationToken ct)
{
using var scope = serviceScopeFactory.CreateScope();
await workItem(scope.ServiceProvider, ct);
}
}

internal async IAsyncEnumerable<Func<CancellationToken, ValueTask>> DequeueAsync(
[System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken ct)
{
await foreach (var item in _queue.Reader.ReadAllAsync(ct))
{
yield return item;
}
}
}


В котором вы по сути кладете функцию в канальчик, а бэкграундный хостед сервис этот канальчик потихоньку разгребает вот так:


namespace Dodo.KnowledgeBase.Web.Services.BackgroundTasks;

public class QueuedHostedService(
IBackgroundTaskQueue taskQueue,
ILogger<QueuedHostedService> logger) : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken ct)
{
logger.LogInformation("Queued Hosted Service is running");

await foreach (var workItem in ((BackgroundTaskQueue)taskQueue).DequeueAsync(ct))
{
try
{
await workItem(ct);
}
catch (Exception ex)
{
logger.LogError(ex, "Error occurred executing task work item");
}
}
}
}


И вот так это можно использовать:

await backgroundTaskQueue.QueueAsync(async (sp, ct) =>
{
var groupAccessService = sp.GetRequiredService<IGroupAccessService>();
await groupAccessService.AssignPredefinedSpacesAsync(existingUser, ct);
});


Вроде несложно, но если что упадет, то всегда можно увидеть в логах в отличие от fire and forget запуска.

В отличие от варианта в доке сделал через IAsyncEnumerable. Так что вышло ну чуть покрасивше и с моей любимой фичей, которую редко когда получается заюзать.
Please open Telegram to view this post
VIEW IN TELEGRAM
8👍21🤝1