#программирование

Жуткая история одного пользователя

На днях я столкнулся с весьма загадочным и мистическим явлением в лучших традициях сериала «Секретные материалы». Аж кровь в жилах застыла. В общем, удалили пользователя из системы, а душа его осталась плутать по закоулкам и пугать все входящие API запросы. Да так, что сторонние системы, которые эти запросы слали, в ужасе шарахались и бросали NullPointerException. Если не хотите спать сегодня ночью, то смело заглядывайте сюда и узрите сию жуткую историю.

Произошло это, как и куча всякого другого дерьма, в 2020 году.

У меня была интеграция, разработкой которой я занимался, и сторонняя система, API которой дергала моя интеграция. Чтобы не путаться, давайте назовем систему Системой, а интеграцию – ни много ни мало, Интеграцией. 

Интеграция моя отвечала за то, чтобы получать на вход email и создавать в Системе пользователей с этим email и другими заданными атрибутами. Если же пользователь уже существовал в Системе, Интеграция должна была получить его по айди и присвоить эти самые атрибуты. Проблема заключалась в том, что айди пользователя нам заранее неизвестен, и никаких способов получения пользователя по email Система не предоставляла. Поэтому мне приходилось итерироваться по всем пользователям в Системе (благо, их там довольно мало, и сильно много их стать не должно) и искать совпадающий email:

users.stream().filter(user -> user.getAccount().getEmail().equals(email)).findFirst();

Особых проблем это не доставляло, и Система возвращала ответ в следующем формате:

"Users": [{
  "id": 42,
  "displayName": "Artem Krutov",
  "account": {
    "id": 42,
    "username": "artem.krutov",
    "email": "user@email.com"
  }
},
{
  ...
}]

Как видно, возвращался нам массив пользователей, и email каждого из них был доступен во внутренней структуре account.

Тщательно протестировав Интеграцию и прогнав несколько реальных сценариев, я отправился на заслуженный отдых.

И тогда это началось…

Шутка, началось все тогда, когда я через интерфейс Системы удалил созданного тестового юзера, чтобы он не путался под ногами, да и в целом, чтобы его никто не видел. А вот когда я его удалил… душа его осталась бродить по длинным и темным коридорам системы.

До поры до времени все было хорошо. Но когда один из пользователей был удален в Системе, и его темная душа начала пугать мои запросы, моя Интеграция начала себя странно вести и бросаться ошибками. Проблема была все в той же строке с итерированием:

users.stream().filter(user -> user.getAccount().getEmail().equals(email)).findFirst();

А все потому, что душа удаленного пользователя все еще присутствовала в ответе Системы:

{
  "id": 42,
  "displayName": "Artem Krutov",
  "account": {
    "id": 42,
    "username": "deleted-42",
    "email": null
  }
}

Видите? Данные пользователя обнулились, но он все равно возвращается в ответе. И, так как Интеграция предполагает, что раз мы нашли пользователя, то должен быть и его уникальный идентификатор в виде email, а его не оказалось, падал NPE:

java.lang.NullPointerException: null
NullPointerException

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

КОГДА ВЫ РАБОТАЕТЕ СО СТОРОННИМИ СИСТЕМАМИ, ОЖИДАЙТЕ ОТ НИХ ПОДСТАВ

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

if (users != null) {
  return users.stream().filter(user -> {
    if (user != null && user.getAccount() != null && user.getAccount().getEmail() != null) {
      return user.getAccount().getEmail().equals(email);
    }
    return false;
  }).findFirst();
}
return Optional.empty();

Всегда относитесь к сторонним системам с подозрением, ибо они в любой момент могут начать слать что-то неожиданное. Проверяйте полученные данные и отвергайте невалидные ответы. Обезопасьте себя от плохих ответов заранее, а не тратьте время на анализ логов, как это сделал я!

Понравилось? Подписывайтесь на меня в соцсетях!

 
Twitter
VK
guest
46 Комментариев
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Татьяна Крутова
Татьяна Крутова
4 лет назад

Кошмар! Впервые вижу настолько костыльное решение для удаления) Системный аналитик во мне негодует, а воображение рисует все трудности отлавливания таких багов. Бррр

Руслан
Руслан
4 лет назад

При сравнении данных в Java всегда лучше вызывать equals от той переменой, от которой есть уверенность что она не null. По крайней мере, я выработал эту привычку у себя. Конечно, это не спасет если аккаунт например null, но зачастую в 90% случаев помогает.

trackback
28 дней назад

buy levitra internet

buy levitra internet

trackback
28 дней назад

viagra para mujer

viagra para mujer

trackback
28 дней назад

pharmacy2u levitra

pharmacy2u levitra

trackback
28 дней назад

tadalafil 5mg para que sirve

tadalafil 5mg para que sirve

trackback
27 дней назад

sildenafil 45 mg

sildenafil 45 mg

trackback
27 дней назад

sildenafil side effects long term

sildenafil side effects long term

trackback
26 дней назад

whats better sildenafil or tadalafil

whats better sildenafil or tadalafil

trackback
26 дней назад

buy tramadol us pharmacy

buy tramadol us pharmacy

trackback
26 дней назад

buy levitra at

buy levitra at

trackback
25 дней назад

how long does cialis work

how long does cialis work

trackback
25 дней назад

free coupons for levitra

free coupons for levitra

trackback
25 дней назад

hims sildenafil review

hims sildenafil review

trackback
25 дней назад

levitra vardenafil

levitra vardenafil

trackback

levitra 10 mg filmtabletten vardenafil

levitra 10 mg filmtabletten vardenafil

trackback
24 дней назад

sildenafil before and after

sildenafil before and after

trackback
24 дней назад

cialis blood pressure side effects

cialis blood pressure side effects

trackback
24 дней назад

sildenafil over the counter cvs

sildenafil over the counter cvs

trackback
23 дней назад

ribavirin online pharmacy

ribavirin online pharmacy

trackback
23 дней назад

cheapest online pharmacy india

cheapest online pharmacy india

trackback

sildenafil vs tadalafil which is better

sildenafil vs tadalafil which is better

trackback
23 дней назад

erectile dysfunction medications

erectile dysfunction medications

trackback

what is the difference between tadalafil and sildenafil

what is the difference between tadalafil and sildenafil

trackback
21 дней назад

carbamazepine and children

carbamazepine and children

trackback
21 дней назад

is celebrex an opioid

is celebrex an opioid

trackback
21 дней назад

tegretol and magnesium deficiency

tegretol and magnesium deficiency

trackback
20 дней назад

taking motrin and excedrin together

taking motrin and excedrin together

trackback
18 дней назад

elavil imitrex

elavil imitrex

trackback
17 дней назад

cilostazol in renal failure

cilostazol in renal failure

trackback
17 дней назад

indomethacin medicines.ie

indomethacin medicines.ie

trackback
17 дней назад

mestinon overdose in dogs

mestinon overdose in dogs

trackback
17 дней назад

can you get high off elavil

can you get high off elavil

trackback

what is diclofenac sodium gel used for

what is diclofenac sodium gel used for

trackback

can you take meloxicam and lyrica together

can you take meloxicam and lyrica together

trackback
10 дней назад

azathioprine for celiac disease

azathioprine for celiac disease

trackback
10 дней назад

maxalt copay assistance card

maxalt copay assistance card

trackback
10 дней назад

lioresal strengths

lioresal strengths

trackback
10 дней назад

piroxicam prati donaduzzi

piroxicam prati donaduzzi

trackback
9 дней назад

allergic reaction to sumatriptan

allergic reaction to sumatriptan

trackback
8 дней назад

what do periactin tablets do

what do periactin tablets do

trackback
8 дней назад

is flexeril or tizanidine stronger

is flexeril or tizanidine stronger

trackback
8 дней назад

artane beaumont community centre

artane beaumont community centre

trackback
8 дней назад

cyproheptadine for akathisia

cyproheptadine for akathisia

trackback
8 дней назад

is zanaflex good

is zanaflex good

Social media & sharing icons powered by UltimatelySocial
46
0
Нравится? Оставьте комментарий!x
()
x