Кейс

Freelance Radar: конвейер мониторинга заказов на Go

Инструмент, который построил для себя и использую ежедневно: мониторинг бирж, LLM-скоринг, доставка в Telegram.

разработка и эксплуатация · Go · PostgreSQL · Telegram Bot API · Claude API · Docker

2площадки
16пакетов Go
15kстрок тестов
2 мининтервал опроса горячей ленты
Первый экран демо: Freelance Radar: конвейер мониторинга заказов на Go

Контекст

Заказ на фриланс-бирже получает первые отклики за минуты, а больше половины профильных заказов на Kwork не получают ни одного: побеждает не лучший, а первый уместный. Ручной мониторинг нескольких лент не масштабируется - либо теряются заказы, либо день уходит на вкладки. Freelance Radar - мой ответ на это: конвейер мониторинга заказов на Go, который я построил для себя и использую ежедневно.

Проблема

У каждой площадки свой формат. FL.ru отдаёт RSS, а полное описание и бюджет прячет на странице заказа. Kwork держит данные готовым JSON внутри HTML и запрещает пагинацию в robots.txt. Бюджеты приходят в разных валютах и видах: фикс, почасовая, «по договорённости». Один и тот же заказ публикуется на нескольких биржах сразу. Поверх всего - шум: накрутки, учебные работы, «за отзыв», на которые нельзя тратить ни время, ни вызовы модели.

Решение

Конвейер из четырёх шагов: сбор, обогащение, оценка, доставка в Telegram. Компоненты не вызывают друг друга - связь только через таблицы PostgreSQL, очередь шага выражена отсутствием связанной записи, падение любого шага не топит остальные. Сбор опрашивает источники в активном окне: FL.ru - раз в 2 минуты, Kwork - раз в 3; вне окна интервалы растягиваются. Двухминутный шаг у FL.ru выбран не «для скорости»: DDoS-Guard пропускает примерно один запрос в минуту-полторы с одного адреса, и более частый опрос упирался бы в защиту. Оценка двухуровневая: сначала бесплатные правила - каталог направлений, свежесть, бюджет, число конкурентов, стоп-слова; в серой зоне подключается языковая модель и сдвигает оценку в пределах заданного потолка, объясняя причину. Прошедший порог заказ приходит карточкой: разбивка оценки, бюджет в исходной валюте и рублях, красные флаги, кнопки «Интересно» и «Мимо».

сбор       -> обогащение -> оценка  -> доставка
биржи         детали        правила    Telegram
раз в 2-3мин  бюджеты       + LLM      2-3 мин

Результат

Подходящие заказы приходят в Telegram за 2-3 минуты после публикации - с разбором, почему заказ набрал свою оценку. Реакции по кнопкам копятся в базе и уже дали первую калибровку весов: пополнились стоп-слова, расширилась серая зона. Собранная база из 1047 заказов легла в основу анализа спроса, по которому построены каталог услуг и этот сайт.

Что было сложным

  • Дедупликация между площадками. Повторы находит отпечаток содержимого: SHA-256 нормализованного текста против доставленного за окно. Дубликат помечается, но не удаляется - тихая потеря заказа хуже лишнего сообщения. Ошибка проверки трактуется так же: fail open в сторону доставки.
  • Мультивалютные бюджеты. Курс Центробанка фиксируется в момент попадания заказа в систему и хранится вместе с ним; получение курсов построено каскадом с запасными путями. Иначе переоценка через неделю дала бы другую цифру без видимой причины.
  • Оценка в два уровня. Правила дёшевы, но не отличают «бота для рассылки клиентам» от «бота для накрутки». Модель вызывается только там, где правила сомневаются. Любой её сбой - таймаут, лимит, невалидный ответ - означает оценку правил без поправки: заказ обязан доехать до чата. Вызовы ограничены суточным потолком.
  • Защита отката миграций. Откат схемы отказывает, если в базе остались данные, которые он исказил бы молча. Один шаг разрешён только с последней версии, многошаговый - только явной целью.
  • Circuit breaker источников. Пять ошибок источника подряд - пауза на час и алерт в Telegram. Частичный результат сохраняется даже при ошибке: упавший запрос не стирает уже собранное.
  • Ноль не равен «неизвестно». Kwork отдаёт число конкурентов, FL.ru - нет. Правило «мало откликов - плюс, много - минус» различает ноль и отсутствие данных и не штрафует заказ за то, что площадка молчит.