Road to senior fullstack dev.
288 subscribers
31 photos
1 video
2 files
61 links
пишу про фулстак, основной канал: @unsleeping706
Download Telegram
https://nekrolm.github.io/blog.html

узнали себя? кто еще не успел выгореть - блог пост от разраба, который 3 года трудился на AWS, на русском
2
Подъехал пост-мортем от Амазона.

С одной стороны, хочется поржать над DNS Enactor, DropletWorkflow Manager (DWFM), Network Manager и прочими — это Galactic от Krazam, только в реальном мире и на очень серьезных щщах.

Если без шуток, то цепочка такая:

1. сначала сломался доступ к dynamodb из-за рейс-кондишена системы управления DNS — два таска начали писать в DNS одновременно, первый старую версию записей, второй — более новую новую, в результате часть записей в DNS оказалась новая, часть старая, второй процесс запустил cleanup, который удалил все старые записи и из такого разломанного состояния система сама восстановиться не могла. Сломалось в полночью, за 50 минут поняли в чем дело и ещё за 40 минут починили руками.

2. из-за сломанного dynamodb, система управления железом не могла обновить статус физических серверов и начала отмечать их как «недоступные», поэтому не могла запустить новые виртуальные машины; после восстановления dynamodb, по-идее всё должно было встать само, но из-за большого объема железа, стоящего в очереди, обновление статуса занимало дольше, чем таймаут — и очередь не разгребалась, а только росла. Коллапс. Стандартной процедуры восстановления для такого случая прописано не было, через 2 часа попыток что-то разрулить, инженеры ограничили число входящих запросов и начали перезапускать тачки с системой управления; это помогло, теперь можно было создать новые виртуальные машины;

3. но ещё какое-то время эти новые виртуалки не делали никакой полезной работы, потому что из-за взрывной нагрузки не справлялась система управления разлива конфигурации сети и сеть на новые тачки приходила с задержкой;

4. из-за этой задержки появления сети на машинах, моргали статусы серверов в лоад-балансерах, отмечая живые инстансы как мертвые и триггерились дополнительные переключения нагрузки (привет, DNS!) и перегрузилась система проверки здоровья серверов,
пришлось её на время выключить.

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


Раздел «что мы поменяем» удивительно короткий и очень технический: починят рейс кодишен в DNS, ограничат объем серверов, который может выключить лоад-балансер и т. д. Ну и заканчивают «извините, в будущем будем более лучше стараться».

Интересно, что они не делают никаких философских выводов из ситуации. Видимо, считают, что идейно всё верно. Я сам такими огромными системами (и командами) не управлял и поэтому осторожно предположу, что, наверное, технически, можно сделать систему проще, но учитывая, что над ней работают десятки независимых команд — это, наверное, минимальный доступный объем сложности и допустимый объем ошибок. Было бы интересно услышать мнение «настоящих сварщиков».



Коллеги советуют замечательную статью на тему безопасности сложных систем. Она не дает ответов, но предостерегает от попытки найти «root cause», «причину аварии» и предлагает посмотреть на безопасность систем по-новому, через другие линзы, чем я привык. Очень рекомендую.
🔥3
Benchmarks Drama или как рандомные бенч привел к тому что все мы с вами получили улучшенную версию JSON.parse()

ref: https://blog.cloudflare.com/unpacking-cloudflare-workers-cpu-performance-benchmarks

не так давно Theo опубликовал бенчмарк с запуском JS Heavy workloads для сравнения на Vercel и Cloudflare Workers, это привело к тому, что Vercel забрали его тесты и опубликовали это в своем блог посте 9 октября, на что Cloudflare Workers (далее CF Workers) сели и за неделю пофиксили большинство проблем out of blue и без явных тикетов, ускорив свою инфру в разы абсолютно для всех кастомеров вне зависимости от тарифов, от чего получили много позитивного отклика на Х

из забавного, они даже пофиксили некоторые проблемы которые улучшили перф и у других провайдеров (об этом ниже)

как утверждают ребята из СF, все артефакты найденные Тео были нетипичны для стандартных процессов которые они тарифицируют - i.e. edge cases

так как Тео сделал пример для нескольких JS Frameworks/Libraries (JS/Next/Svelte) они поняли, что это не проблема какой-то выделенной технологии, это проблема именно инфры которую они поставляют, так же, если бы Тео остановился только на Next, все бы пришли и сказали, ну конечно, бро, Vercel так сделал чтобы Next работал на их платформе быстрее чем где бы то еще

Теперь еще раз подчеркнем отличия серверлесс:
Vercel (другие платформы которые используют Lambda напрямую) имеют 1 VM per request.
Cloudflare имеет 1 isolate per request (тогда как VMs are shared with others code/devs) (немного описывал это здесь)

ну раз VM разогреты, linux инстанс уже поднят, значит ли это что на CFW нет холодных стартов? не совсем, даже запущенный инстанс может не иметь вашего кода внутри, и CF Worker пойдет запрашивать ваш JS код и положит его внутрь изоляции, и иногда может быть так, что проще вас будет перенаправить в другой регион (на другой инстанс), это займет доп время, но зато код там уже присутствует и его не надо запрашивать. Так же не стоит забывать про случай, когда у вас есть инстанс, который уже занят запросом, и который почти его закончил, выгоднее же будет на него закинуть новый запрос, чем поднимать новый инстанс, грущить в него ваш код, запускать его, даже если текущий почти освободившийся инстанс находится чуть дальше, - нюансов куча, как видите

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

теперь к разбору проблем которые были обнаружены CF Workers:

- первая проблема была связана с тем, что текущая политика обработки/поднятия инстансов была рассчитана на холодные старты тяжелых приложений, таких как Next с их тяжелой инициализацией. то есть политика была оптимизирована на latency и пропускную способность (ищите поиском тут Database Performance at Scale #) сквозь миллионы запросов, но оказалась менее оптимальной для CPU зависимых процессов

после того как они поняли проблему текущих эвристик их алгоритма для заданных входных параметров, они смогли обновить алгоритм и эффективно управлять авто-масштабированием: I/O зависимые процессы попадали в уже "горячие" инстансы, в то время как CPU зависимые направлялись так чтобы не блокировать друг друга (график как поменялось после глобального релиза на всех юзеров для всех планов прикреплю в комменты)

второй забавный факт - CF забрали бенчмарк Тео и теперь он запускается у них внутри каждые 1мин, так что не бойтесь замерять бенчи и публиковать, возможно, ваш код возьмут корпораты в прод (и даже не заплатят вам за это), но потешить свое эго можно (и сказать потом всем что именно вы занимаетесь РЕАЛЬНЫМИ вещами и напрямую влияете на состояние экосистемы)
👍3
- затем описаны детали связанные с настройкой памяти в V8: CF рассказали что в 2017 настраивали эту память по официальным рекомендациям, но на дворе уже 2025 год и эти лимиты / рекомендации давно поменялись. После тестов оказалось, что со старыми рекомендациями GC запускается чаще, чем можно, они убрали этот жесткий лимит и позволили V8 самому лимитировать "young space size" на основе внутренних эвристик, данный фикс позволил УЖЕ поднять перф бенча Тео на 25%

кому интересно, посмотрите сколько они открыли небольших PR изучая перф OpenNext адаптеров под Next. Удаление ненужных аллокаций / ненужных копии и создание вместо этого явных констант, которые используются дальше внутри стека вызовов. Команда CF Workers уточняют, что они только начали и не планируют останавливаться. Импакт, который они занесли в экосистему OpenNext (и в Next) большой, так как цель OpenNext - сделать Next максимально быстрым на любой платформе/хостинг провайдере

- Web стримы медленнее NodeJS стримов, CF Workers работают на веб стримах, тогда как код некста написан на нод стримах, полифилы не делают их настолько быстрее, но делают совместимыми

- СF на этом не остановились и пошли делать импрувы во всю экосистему ускорив json.parse(), мем на этот счет тоже оставлю в комментах

в json.parse(JSON, reviver) можно передать функцию чтобы эффективно управлять тем как JSON будет парситься, минусы этого подхода в том, что данная функция будет вызвана на каждую пару ключ/значение внутри JSON структуры

и это проблема всей экосистемы, CF решили не смиряться с этим, и сделали патч V8 (у них есть отдельная команда которая контрибьютит туда), и в итоге улучшили JSON.parse() на 33%

- другая интересная особенность была с тригонометрическим бенчем, когда простое перемножение синуса на косинус 1млн раз приводило к каким-то невероятным вычислениям, умные дяди знающие ноду залезли в сурсы и обнаружили однострочный фикс: нужно оказывается просто включить возможность v8 использовать нативные функции для тригонометрии

но пошли они изучать это только потому, что бенч на тригонометрии работал быстрее на Workers нежели чем Node.js на Vercel, и так как Сloudflare не делает ничего с этими функциями у себя, их это заинтересовало, и они нашли что кто-то где-то не включил данную опцию. не скрыв свое исследование, а наоборт публично раскрыв детали, CF Workers не получат никаких бенефитов, так как у них уже стоит нужный флаг, но это позволит AWS, Vercel (и возможно другим провайдерам) включить данный флаг у себя и улучшить перф абсолютно для всех юзеров

Поэтому, друзья, не бойтесь делать бенчи и делиться своими результатами!
👍4
Road to senior fullstack dev.
https://blog.cloudflare.com/code-mode/
небольшая выжимка:

- MCP неправильная абстракция, хоть мы и привыкли строить/видеть продукты построенные на чужих бизнесах (как Vercel на AWS), они все были призваны решить какие-то проблемы. MCP как инструмент появился и люди не успели ощутить боли от такого использования, в то время как ИИ пузырь раздулся настолько, что начали появляться все новые и новые инструменты вокруг этого

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

- наличие тулов раздувает входное окно (input tokens) с каждый вызовом тула, чтобы представить это, подумаем над таким промптом: "что мне надеть", модель пойдет в тул памяти чтобы достать о вас хоть какие-то сведения, далее результат этого тула передаст в тул о запросе погоды по вашей геолокации, ну и с каждой итерацией контекст расходуется. решение? иметь изолированную среду с минимальным набором инструментов, просить нейронку генерировать код, который сходит во все АПИ (и даже условно, если понадобится), и сделает это за один круг, таким образом получим возможность вызвать все тулы разом без раздува входного окна

реф: https://www.youtube.com/watch?v=bAYZjVAodoo
вчера произошел исторический в моей карьере момент, когда меня все-таки включили в fullstack-flow, компания наша набирает в большинстве своем fullstack разработчиков, ну или чисто бекендеров, только недавно мы начали принимать чисто фронтов (я думаю история началась с меня), так вот, организовали буткамп, как известно мы делаем коннекторы к существующим API чтобы быть Fivetran compatible

текущий онбординг мне понравился, была пара встреч, ребята подготовили доку, расжевали ключевые части, и наметили майлстоуны. в текущей инфре уже был сетап темплейта, частично код был с элементами легаси, частично присуствовала документация к модулям/интерфейсам/классам. Сложно было усвоить все и сразу, все еще ориентируюсь "на ощупь" в этом, но мне помогли ребята, которые уже гуру в таких коннекторов (у нас их на компанию 150+). Так как за почти 7 месяцев я им успел помочь разобраться в тонкостях реакта, они все искали возможность ответить мне помощью на помощь, и вот им вчера был дан такой шанс, они не могли поверить, что мне выдали такую задачу (я 2+ месяца ее ждал и просил), так что было приятно видеть с какой отдачей и рвением они стремились мне объяснить внутряк и помочь разобраться/сделать правильно
8
На прошлой неделе мой буткамп по созданию ETL коннектора успешно завершился, я даже собрал себе некоторое бинго из кейсов, которые я успел покрыть в рамках этого процесса

судя по отзыву коллег с API документацией мне повезло, я смог быстро нащупать поле курсора для таблицы (мы хотим делать инкрементальные синхронизации если возможно, а не полностью перезаписывать данные, так как это быстрее и дешевле с точки зрения инфры), так что обе возможности синхронизации (Full Refresh, Incremental) я покрыл, остался только CDC, возможно в следующий раз, когда поиграемся с таблицами

у нас очень хорошая система для быстрого создания скелетона + хорошие абстракции для переиспользования. иногда возникает задача создать подтаблицу с foreign key референсом, и в текущей системе есть 3 способа этого достичь (смог попробовать их все):
- map (schema-driven, самый простой, описываешь схему, существующий механизм далее сделает все за тебя), если айтем не пришел ничего не создасться
- splitTo, когда таблица приходит объектом, а не массивом, но не falsy (не все кейсы покрыты)
- трансформация после схемы (можно покрыть любой сценарий, но не такая оптимальная, так как вызывается на каждый рекорд который мы формируем)

внутрь бинго так же попали:
- подтаблица внутри подтаблицы
- обогащение данных в момент обработки батчей (когда нужно дополнительное поле прокинуть в сабтейбл, но не хочется уходить в трансформаци после схемы из-за дополнительного цикла)
- хеширование для записей с подписью (читайте как signed imageUrl from S3 to create Primary Key)
- хитрый способ запустить Full Refresh для таблицы с поддержкой Incremental и записать ее lastRecordTimestamp, чтобы была возможность затем запустить синхронизацию таблицы инкрементально без необходимости все равно делать Full Refresh каждый первый инкрементал запуск
- для вычисления lastRecordTimestamp внутри коллекции использовал хак того, что апи возвращает данные отсортированные уже постранично, так что после валидации я взял просто timestamp от первого айтема

большое спасибо ребятам за лекцию и помощь, иногда я их выдергивал на пару часов из своих задач, чтобы они смогли мне рассказать чуть подробнее: что/как/почему это у нас
Читаю сейчас как ребята делали Bluesky и удивляюсь их подходу flexibility over scalability. Они преднамеренно оставляли возможность поменять в корне структуру приложения в процессе исследования, надо бы взять на вооружение, лично я всегда делаю что-то наоборот (но по итогу все равно вижу, как меняются заложенные процессы со временем)

https://newsletter.pragmaticengineer.com/p/bluesky

Building for flexibility, not scalability, was deliberate. The idea was to swap this approach to prioritize scale once everyone knew exactly what to build. The knowledge that decisions are hard to undo made the team’s own decision-making more thorough, Daniel reflects:

“The most difficult part of building Bluesky has been the constant awareness that small decisions you make may be locked in for years and have ripple effects. In a decentralized environment, these can be difficult to unwind. It puts a lot of weight on every decision, and we have to double and triple check choices that we make so that we hopefully don’t regret them.”
2
пока первый канал получает все мое внимание через отложенные посты и драфты, анонсирую чуть новостей тут, а то пылится

вскоре начнем собирать hybrid deployment, хотим упаковать часть нашего функционала в SEA(single executable application). некоторые клиенты хотят получить возможность взаимодействовать с нашими сервисами, но это банк и безопасники не дадут возможность завайтлистить наши айпишники.

поэтому планировали отделить часть функций и завернуть это все в докер. из-за того что у нас все на typescript, а код светить не хочется, думали переписывать на более низкоуровневые языки которые можно собрать в бинарник, остановились на go, но потом со мной поделились референсом о том, что нода последних версий уже умеет в SEA, типы можно заменить пробелами (вырезать), и так же собрать бинарник, поэтому будем пробовать SEA, если не все там сработает перепишем на go 💅💅
🔥3
погружался сегодня в сокетные подключения на бекенде и обнаружил что у NodeJS таймеров есть замечательный метод unref()

NodeJS.Timeout.unref(): NodeJS.Timeout

When called, the active `Timeout` object will not require the Node.js event loop to remain active. If there is no other activity keeping the event loop running, the process may exit before the `Timeout` object's callback is invoked. Calling `timeout.unref()` multiple times will have no effect.


делюсь находкой с вами

читать далее: https://httptoolkit.com/blog/unblocking-node-with-unref/
👍3
напросился я таки на реально интересные и сложные задачи выходящие за рамки перекладывания json и общения с third party api. пакуем часть функционала нашего сервиса чтобы отдать его в виде SEA (single execution application) для того, чтобы файлы клиента, которые мы переносит из источника в приемник, не выходили из приватной его сети. в основном это связано с комплаенсом (ну и нагрузку инфры нашей это снизит чуть.

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

пока играюсь с вебсокетами на nest.js, смотрю на dockerode (doker sdk) и собираю пазлы. настолько это все нравится, что сижу вечерами как с пет проектом, хотя вроде как работа

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

вчера произошел ВАУ момент, когда я соединил три бранчи и наконец-то начал стрелять из постмана в своей сокет gateway локальный и смотреть насколько мои гипотезы сработали
👍4
Road to senior fullstack dev.
напросился я таки на реально интересные и сложные задачи выходящие за рамки перекладывания json и общения с third party api. пакуем часть функционала нашего сервиса чтобы отдать его в виде SEA (single execution application) для того, чтобы файлы клиента, которые…
прошла неделя со старта, всю неделю вечерами я сидел и ковырялся в этой системе. пазл начал собираться, части начали подключаться друг к другу и общая картина начала проявляться. вот теперь я уже могу создать агента в интерфейсе и подключиться к нему локально, до этого я его создавал руками в базе. уже сегодня планируем поревьювать мои (агентские) имплементации, определить последующие действия. столько нового узнаю за это время, это колоссальный опыт и я рад, что меня позвали принять в этом участие, я все еще скептически настроен на интеграцию, все еще не могу поверить что агенты такие сильные, хотя чисто с точки зрения паттернов код они разбирают грамотно (потому что я их просил об этом), ну и лиду нравятся мои подходы. посмотрим где это все посыпется и через что еще придется пройти. сегодня так же будем реверс инженирить конкурентное решение, выгрузили их логи
👍3
Road to senior fullstack dev.
прошла неделя со старта, всю неделю вечерами я сидел и ковырялся в этой системе. пазл начал собираться, части начали подключаться друг к другу и общая картина начала проявляться. вот теперь я уже могу создать агента в интерфейсе и подключиться к нему локально…
продолжаю делиться майлстоуном, пазл коммуникации между сервисами окончательно сложился, приоткрываю завесу и вам.

Какие сущности есть? (картинку прикрепил).

На стороне облачной инфры сидит бекенд + gateway. Локально у клиента поднят Agent (не AI). Задача Agent быть тонкой прослойкой для коммуникации с бекендом через gateway имея в запасе лишь relay/request методы и ни имея доступы к бизнес логике. Вся бизнес логика, схемы, паттерны, флоу запусков хранятся в облаке. Агента требуется поднять на удаленной инфре непосредственно потребителя. Как только агент поднимается, он подключается к нашему бекенду через вебсокет. На стороне гейтвей мы уже видим, что агент подключен, обрабатываем подключение/отключение, слушаем ивенты от него и бекенда и выступаем в роли прокси слоя. С бекендом мы общаемся по TCP, это отдельный микросервис.
Road to senior fullstack dev.
продолжаю делиться майлстоуном, пазл коммуникации между сервисами окончательно сложился, приоткрываю завесу и вам. Какие сущности есть? (картинку прикрепил). На стороне облачной инфры сидит бекенд + gateway. Локально у клиента поднят Agent (не AI). Задача…
Как только планировщик бекенда понимает, что надо запустить процесс на удаленной машине, мы ловим tcp ивент на gateway, и направляем нужную команду через WS агенту, который в свою очередь умеет поднимать локально инстансы воркера для обработки этого процесса. Вся коммуникация шифруется. Данные клиента обрабатываются не выходя из приватной сети. Агент лишь отправляет метадату для понимания статуса обработки.

Теперь недельные gotchas:
- успел разобраться в различиях между MessagePattern / EventPattern: в одном случае мы кидаем ивент и не ждем результата, в другом ждем ACK и перенавляем ответ через вебсокет.
- разобрался как потестить event/message в постмане (там не все так очевидно), как прокинуть auth через headers, пришлось для этого делать ветвление в логике чтобы уметь доставать из headers или из handshake конфига
- разобрался в том, как у нас в целом работает основной поддомен, так как раньше не лазил туда, построил на этом хорошую типобезопасную систему на основе зод схем + валидации, основной поддомен работает с any/unknown как пейлоад. Поэтому тут мы получаем впридачу intellisense
- после улучшения понимания картинки, начал выделять вертикальные слайсы логики в отдельные сервисы для лучшей поддержки и масштабирования
- заменил nodejs интервалы на крон процессы (мы мониторили stale агентов, которые были онлайн, но потом по какой-то причине не присылали ping хелзчеки, чтобы потушить их и не считать как подключенных)
увлекательная история о том как совсем недавно мы чуть не допустили бекдор в ssh/linux. атака почти удалась, небезразличный разработчик postgresql заметил 0.5сек лаг и это не давало ему покоя, так и обнаружился бекдор

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

refs:
https://www.youtube.com/watch?v=aoag03mSuXQ
https://www.cve.org/CVERecord?id=CVE-2024-3094
Hybrid Deployment end-to-end (предыдущая часть и дополнение)
продолжаю делиться прогрессом по on-premise/hybrid deployment, который мы собираем вот уже почти месяц.
спустя еще 2 недели с последнего чекпоинта мы:
- закрепили окончательно коммуникацию между всеми частями системы (микросервисы на бекенде + клиент + локальный агент)
- протестировали неуспешные сценарии (до этого тестировали happy path)
- добавили обработку сброса запуска интеграции (напоминаю, что у нас JIT - just in time докер контейнеры, которые поднимаются по команде для экономии ресурсов)
- настроили multi-tenancy (для изоляции данных), до этого mongoose плагин был отключен на коллекциях mongoDB которые завели под агентский менеджинг. для этого пришлось добавить два интерсептора на ws/tcp протоколы, вебсокетный мы положили в мидлвару сокет сервера, который по конекту определял агента, доставал его tenantId и клал в контекст общений. tcp коммуникация была обогащена tenantId внутри полезной нагрузки команд запуска/прерывания интеграции.
- прокачали часть визуала на клиенте (напоминаю, что продакта мы пока не привлекали, весь визуал делаем сами, насмотренности хватает, получилась пушка!).
- подключили сиай для всех трех модулей: agent, agent-gateway, client/hybrid-deployment
- ограничили импорты для модели с токеном (где хеш сидит), чтобы был доступ только внутри одного единственного сервиса где вся работа с проверкой хеша и происходит (защищаю от обезьяны с гранатой)
- унесли валидации полезной нагрузки для событий/сообщений в декораторы, теперь сервисы содержат полезную бизнес логику, валидация живет отдельно и код читается как книжка
- установили механизм ретраев (чтобы агент смог переподключиться). в текущее время agent gateway представляет собой SPOF (single point of failure), если он временно выйдет из строя - агент сможет к нему переподключиться.
- начали возвращать ошибки полученные на agent-gateway обратно на UI через микросервисную коммуникацию (если агент был не найден для исполнения интеграции on premise или находится не в сети)
- провели 2 демо для VP Engineering и для CEO/CTO, испытали там наши решения, коммуникацию между всеми частями системы, придумали как усилить решение с точки зрения безопасности, обсудили будущие приоритеты, пока работаем над этим. по итогам демо я теперь могу запускать интеграцию на одном устройстве с помощью агента, выступая локально бекендом.
- разобрались с проблемой кеширования локального запуска докер образов (до этого приходилось иногда руками пересобирать nx пакет в монорепе чтобы отразились последние изменения), решили это инъекцией этой зависимости только в локальной сборке
- усилили обработку ошибок, границы перехватов поставили только на уровне контроллеров, ошибки из сервисов поднимаются на самый верх, это помогло убрать вложенные try/catch и облегчить readability бизнес логики в доменных сервисах

покрыли гипотезы на которых построена логика обработки ошибок тестами, было проще написать тесты, чем придумать как это воспроизвести. я понимал что это скорее необходимость, чем запрос, так как сложность возрастала по мере увеличения распределенности системы. каждая граница должна смотреть на любую входящую коммуникацию с точки зрения zero-trust/XP (extreme programming) пока мы не настроим mTLS (а это мы пока вынесли из v1, так как у нас микросервисы не умеют в такое на самом бекенде). из такого подхода появилось множество проверок:
- перед исполнением команды, проверь что агент онлайн
- при получении команды убедись что tenantId полезной нагрузки команды совпадает с тем, который присвоен текущему агенту, который получил эту команду (чтобы нельзя было интеграцию запустить с чужого агента)

затем проверили сценарии подключения к сокету на уровне agent-gateway:
- постучались с неверным токеном
- постучались с верным токеном, но агента не нашлось в базе
- постучились с верным токеном, агент есть, но без tenantId
- постучались с токеном, который не прошел верификацию

далее дополнили тесты на нужные доменные ошибки, которые добавил в relay (fire and forget), request (fire, wait till ack, return response). Из доменных ошибок наиболее яркие: InfrastructureError, DatabaseError, AgentNotFoundError, AgentOfflineError
2
после этого я решил не копить технический долг и пройтись агентом по структуре трех пакетов монорепозитория для того, чтобы улучшить контекст, уменьшить когнитивную нагрузку путем переименования модулей/переменных/интерфейсов для более явной передачи смысла. наш взгляд уже успел замылиться за 9200+ LoC. решил я открыть ризонинги LLM и обнаружил, что агент смог найти небольшое количество багов в интерфейсе, которые просочились без внимания. причиной тому, что мы пропустили этот баг был легаси стейт и огромный кусок неподдерживаемого кода + отдельный сценарий похожего компонента в котором много чего смешано, в общем базовый "так исторически сложилось", который пополняется лишь патчами, а не переписыванием, а все баги чинятся постфактум, никто не хочет брать ответственность за внесение изменений полным рефакторингом (обычно меня отдельно благодарят за то, что я беру за это ответственность). учитывая что агенты уже очень хорошо справляются с рефакторингом, полное переписывание такого объемного куска легаси кода тоже выйдет дорогим, так как никто не знает об edge кейсах, даже и их написать через агента будет дорого, потому что это надо будет пройти согласовать через круг неизвестных лиц, которые сами не понимают как эта фича должна работать, чтобы смело ее переписать правильно, но время придет, я верю в себя и в других людей, которым "не безразлично"
3👍2