Привет, Хабр! Мне 14 лет, и пока мои ровесники ругаются в cs2, а нормальные люди спят по 8 часов, я решил, что мне катастрофически не хватает стресса в жизни. Поэтому за последний месяц я написал собственную платформу для решения алгоритмических задач — с изолированным выполнением кода, микросервисами и котиками.
Встречайте — ЛитКот. Проект уже крутится в проде на leetcot.ru, а в этой статье я расскажу, как организовать архитектуру такого сервиса, не задохнуться в монорепе и защитить сервер от мамкиных хакеров (вроде меня самого).
Зачем нужен ещё один тренажёр?
LeetCode — это классика, но давайте честно: решать сухие задачи про инверсию бинарного дерева бывает невероятно скучно. Особенно когда на реальном собеседовании тебя попросят просто отцентрировать div или переложить JSON из одной апишки в другую. Мне захотелось добавить геймификации, сюжета и немного (а точнее, нездорово много) безумия.
Например, в моём курсе «Щёлкаем алгоритмы как рыбку» нет унылой задачи «Поиск элемента в отсортированном массиве». Зато есть «Прятки с сосиской»! Пользователю нужно написать алгоритм бинарного поиска за O(log n), чтобы помочь коту найти сосиску в контейнерах. Согласитесь, ради виртуальной сосиски писать код как-то приятнее, чем ради мифического оффера в бигтех.

Выполнение кода: даём пользователю гранату (и надеемся на лучшее)
Самое весёлое в разработке аналога LeetCode — это запуск чужого кода. Разрешить случайным людям из интернета выполнять Python-скрипты на твоём сервере — это как добровольно пригласить в дом полтергейста. Один случайно (или специально) запущенный while True: fork() — и твой сервер со слезами отправляется в Вальгаллу, попутно наматывая счёт за хостинг до астрономических высот.
Пришлось продумать надёжную изоляцию процессов. Код каждого пользователя выполняется в изолированной песочнице со строгими ограничениями по памяти и жёстким тайм-аутом. Не успел найти сосиску вовремя — лови Time Limit Exceeded и иди оптимизируй. У нас тут суровый кошачий киберспорт.

Инфраструктура, или «Я у мамы DevOps»
Чтобы проект не жил только на моём localhost, я настроил полноценный CI/CD-пайплайн в GitHub Actions. Проект пакуется в Docker-контейнеры с аккуратным Dockerfile и .dockerignore, чтобы случайно не утянуть в прод папку node_modules весом с небольшую чёрную дыру.
Для удобной разработки настроены DevContainers — настраивать локальное окружение руками каждый раз это для слабаков.
А чтобы после моих гениальных релизов не отваливались вёрстка и логика, прикручены E2E-тесты на Playwright. Да, я даже пишу тесты. Сам в шоке.
name: Deploy Productionon: release: types: [published]jobs: deploy: runs-on: self-hosted steps: - name: Cleanup host run: | docker system prune -af --volumes sudo journalctl --vacuum-size=10M sudo apt-get clean - uses: actions/checkout@v4 - name: Environment run: | [ -f /home/user1/actions-runner/secrets.env ] && cp /home/user1/actions-runner/secrets.env ./.env || exit 1 - name: Update and Deploy run: | docker compose pull docker compose up -d --remove-orphans - name: Migrations run: | docker compose exec -T app pnpm --filter @repo/db exec prisma migrate deploy
Что дальше?
Месяц плотного кодинга на энтузиазме дал свои плоды. Проект работает, пользователи могут учить алгоритмы, а котики находят свои сосиски.
Но почивать на лаврах скучно. Прямо сейчас я готовлю к релизу следующий проект -и это будет кое-что большее чем просто тренажёр задач. Следите за leetcot.ru и arlist.ru.
Буду рад конструктивной критике (и неконструктивному хейту) в комментариях. Пишите, как вы реализовывали безопасное выполнение кода в своих пет-проектах, ставьте плюсики и буду рад увидеться с вами вновь!
ссылка на оригинал статьи https://habr.com/ru/articles/1050358/