- PVSM.RU - https://www.pvsm.ru -
При разработке стратегии email-аутрича была поставлена задача: без готовой базы B2B-контактов ежедневно находить новые B2B-компании, которые подходят под ЦА, и распределять их по сценариям коммуникации.
Источник подобран был такой, куда компании сами каждый день заливают информацию о себе: агрегаторы вакансий, названия которых мы много раз слышали. И самим сигналом к сбору информации был выбран как раз факт недавнего размещения вакансии. И тут сразу довольно удобный вход в пайплайн — если организация размещает вакансию, значит какие-то процессы в ней живут и можно рассмотреть для дальнейшей квалификации. Однако между получением сигнала и первым письмом стоит длинная цепочка квалификации, некоторые операции в ней дорогие и ненадёжные.
Как выглядит весь путь: вакансия → компания → домен → контакт → проверка → распределение.
На выходе должна быть распределенная по кампаниям база релевантных компаний с контактами, без дублей и без потери информации. И вот такой пайплайн должен прогонять через себя около 20 000 контактов в месяц.
Сразу же видны сложности:
часто компании размещают больше одной вакансии, значит будут дубли;
сайты и внешние сервисы могут не ответить;
результаты DNS и SMTP проверок бывают неоднозначными;
процесс может упасть между операциями.
Поэтому задача свелась к тому, чтобы превратить эту цепочку в воспроизводимый конвейер: дешёвый на входе, не принимающий временную ошибку за окончательный факт и устойчивый к сбоям.
На маленьких объемах кажется логично построить цепочку так: получили компанию, открыли сайт, нашли email, проверили доступность по DNS/MX/SMTP и передали дальше.
И здесь приходится решать первый затык. Как бы сделать так, чтобы при масштабировании не тратить ресурсы на одинаковую проверку всего объема? Под ресурсами я имею в виду не только деньги. Внешние запросы занимают время, рабочий слот и часть лимита сервиса, к которому мы обращаемся. Поэтому этапы нужно было ранжировать по их стоимости.
Например, нормализация домена (https://www.Example.ru/about [1] → example.ru) выполняется локально и относительно дешево. DNS-запросы тоже, для одного домена нужно сделать несколько коротких запросов.
А вот начиная с изучения сайта начинается разветвление и множественные запросы. Схема crawler’а по 1 компании:→ 1 домен→ несколько страниц→ несколько emailИ потом каждый найденный адрес потребует отдельную проверку…
А если одна компания пришла из нескольких вакансий, вся эта цепочка может запускаться снова и снова. Вместе с таймаутами и временно недоступными серверами одна лишняя запись на входе превращается в несколько ненужных запросов.
Поэтому перед запуском crawlerа и проверкой адресов мы поставили дешевые этапы:
раннюю дедупликацию по id работодателя (employer ID) и нормализованному домену;
техническое профилирование домена по DNS/SPF. Оно по заранее настроенному скорингу определяет — передаем дальше или нет.
Первый этап — удаление дублей. Источник может отдать несколько вакансий одного работодателя, но employer ID у них будет одинаковым. Такие записи схлопываются. Дополнительно система проверяет журнал уже обработанных компаний и исключения по названиям: крупные федеральные и заведомо неподходящие организации.
Второй этап, DNS/SPF-профилирование, запускается, как только ссылка свелась к стандартизированному домену и все его дубли схлопнулись. Здесь классификатор определяет, какие серверы могут отправлять почту от имени домена и технический score.
При попадании score в определенный диапазон по сайту стартует crawler. (Соответственно, в противном случае более дорогая обработка домена не начинается). Результат скоринга кэшируется и для одного домена больше не повторяется.
Для всего процесса на этом этапе существуют несколько параллельных воркеров, которые при этом имеют лимиты, поэтому не перегрузят endpoint.
Здесь начинается дорогая часть пайплайна. Crawler обходит сайт, ищет корпоративные почты, а следующим этапом проверяет их через валидатор.
Сначала парсер открывает главную страницу и найденные там внутренние ссылки, потом проверяет стандартные разделы вроде /contacts, /team и /about. Количество страниц и время обхода ограничены, чтобы один медленный сайт не занимал рабочий слот бесконечно.
Все найденные адреса почт прогоняются через валидатор, который проверяет синтаксис и тип почты: ролевая, корпоративная, бесплатная, одноразовая. Потом проверяем DNS и MX-записи, чтобы понять, принимает ли почта письма. После этого всего обращаемся к серверу почты по SMTP без отправки письма и по ответу понимаем: готов он принять сообщение или нет.
На этапе валидации существует отдельная проблема — catch-all почты. Они принимают любые запросы, даже если получателя не существует. Поэтому по SMTP нельзя отличить реальный ящик от несуществующего. При этом временная ошибка DNS или недоступность сервера тоже не означают окончательного отказа: причина может исчезнуть при следующей проверке.
Исходя из причин выше, валидатор возвращает не только valid или invalid, а несколько технических статусов:
подтвержден
отклонен
catch-all
временно не проверен
ролевой
бесплатный
одноразовый.
Общий пайплайн на этом моменте разветвляется на несколько сценариев в зависимости от полученного score. Во-первых, с первой пачки компаний были созданы 3 постоянные кампании, каждая со своей цепочкой писем. Они созданы один раз и далее между ними как раз и распределяются новые почты из пайплайна.
Вместе с почтой кампания получает название компании, сайт, источник и рейтинг скоринга. И перед загрузкой каждая строка дополнительно проверяется на дубли по почте во всех кампаниях и на наличие почты в стоп-листах. И если дневной лимит позволяет и все проверки пройдены — контакт уходит в работу.
После передачи контакта система должна сохранить локальный статус компании как обработанной. Как раз здесь и может возникнуть главная проблема: контакт уже мог попасть в конечную систему, а локальный статус ещё не успел обновиться.
На финальном этапе происходят две раздельные операции передача контакта в запущенную кампанию и локальное сохранение ее статуса.
То, что эти шаги существуют раздельно, и создает прореху. Контакт уже мог передаться, а статус еще не сохраниться. Если процесс упадёт в этот момент, при следующем запуске компания снова попадёт в обработку и система повторит передачу.
Логичное решение: сначала отметить компанию обработанной, а потом передать контакт, поменять операцию местами. Ну и да, дублей станет меньше. Как и контактов в запущенных кампаниях) Потому что в таком случае, при падении процесса между шагами, теряется вся строка, хотя считается обработанной.
Поэтому мы сделали не так, а выбрали подход “at-least-once”. То есть контакт в цепочке должен быть передан как минимум 1 раз. А мы не блокируем контакт, который возможно есть на следующем шаге, а удаляем его дубль в случае обнаружения. Но при этом, не теряем ни одной строчки информации. Система проверяет на дубли и не создаёт вторую запись, если уже получала ее раньше
И на финал кейса и самой воронки остается только одно: отловить краш и самой восстановиться.
Во-первых, существует система атомарной блокировки. Не получится запустить два одинаковых прогона. Пока процесс работает, он регулярно обновляет heartbeat, служебную отметку об активности. Если он давно не обновлялся, запуск считается зависшим и автоматически закрывается с возможностью быть запущенным повторно.
Такие завершенные запуски пропускаются, а компании без статуса возвращаются в работу. Здесь точкой восстановления будет журнал, в который записывались данные на этапе дедупликации. К тому же временные проблемы допускают повторы, поэтому отдельные ошибки не будут стопить весь пайплайн.
С одной вакансией на входе, на выходе мы получили проверенный контакт, загруженный в одну из 3 кампаний соответственно своему скору. По сути 2 простых правила: сначала дешевое, потом дорогое + доверяй статусу, но проверяй, сделали такой пайплайн реализуемым.
Прямо сейчас через него проходят до 20к контактов в месяц без значимых косяков и существенных затрат.
Автор: Smartmarketer
Источник [2]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/dns-2/456592
Ссылки в тексте:
[1] https://www.Example.ru/about: https://www.Example.ru/about
[2] Источник: https://habr.com/ru/articles/1070562/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1070562
Нажмите здесь для печати.