Все статьи из цикла AWS

Еще одна история о том, как Амазон может попить крови.

Напомню особенности нашей архитектуры. Сервисы записывают в S3 сущности разных типов. Их может быть много, например, полтора миллиона такого-то типа. Чтобы выгрести сущности разом, мы используем чудо-оружие Амазона — сервис Athena. Он собирает файлы из бакета и склеивает в один CSV.

Среди сущностей встречаются выбракованные, и при обходе CSV их нужно игнорировать. Один из признаков брака — вложенное поле attrs, которое равно null. Не проблема: получаю ленивую коллекцию сущностей и накладываю на нее фильтр:

(->> csv
     (get-lazy-seq ...)
     (filter
      (fn [entity]
        (-> entity :attrs nil?))))

На проде, по различным логам и эксепшенам, вижу, что битые сущности просочились в обработку. Как так?

А вот как: в оригинальном JSON поле attrs было null, все верно. Но при агрегации в CSV Амазон экранирует null кавычками и получается \"null\". При этом его не волнует, что null находится в середине JSON-строки, которая уже экранирована. Какой-то парсер доходит до null и пишет его с кавычками.

В результате при чтении JSON получается {"attrs": "null"}, то есть строка с буквами n, u, l, l. Чтобы выкинуть эту запись, я переписал фильтр так:

(or (-> aggregate :attrs nil?)
    (-> aggregate :attrs (= "null")))

Спрашивается, зачем я оставил первый вариант с чистым nil? Потому что, если однажды мы перейдем на другое хранилище, поле опять станет null вместо "null", и фикс придется откатывать. А так оба случая покрыты: и нормальный, и кривой.

Разумеется, прикол с null нигде не описан, в Гугле ничего нет. Счастливой отладки, уважаемые коллеги!

Вот так я потерял еще один день. Каждый раз, распутав новый квест от Амазона, откидываюсь в кресле и тихо матерюсь. А затем иду дальше.