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

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

На днях я столкнулся с весьма загадочным и мистическим явлением в лучших традициях сериала «Секретные материалы». Аж кровь в жилах застыла. В общем, удалили пользователя из системы, а душа его осталась плутать по закоулкам и пугать все входящие 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
58 Комментариев
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Татьяна Крутова
Татьяна Крутова
4 лет назад

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

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

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

trackback
3 месяцев назад

buy levitra internet

buy levitra internet

trackback
3 месяцев назад

viagra para mujer

viagra para mujer

trackback
3 месяцев назад

pharmacy2u levitra

pharmacy2u levitra

trackback
3 месяцев назад

tadalafil 5mg para que sirve

tadalafil 5mg para que sirve

trackback
3 месяцев назад

sildenafil 45 mg

sildenafil 45 mg

trackback
3 месяцев назад

sildenafil side effects long term

sildenafil side effects long term

trackback
3 месяцев назад

whats better sildenafil or tadalafil

whats better sildenafil or tadalafil

trackback
3 месяцев назад

buy tramadol us pharmacy

buy tramadol us pharmacy

trackback
3 месяцев назад

buy levitra at

buy levitra at

trackback
3 месяцев назад

how long does cialis work

how long does cialis work

trackback
3 месяцев назад

free coupons for levitra

free coupons for levitra

trackback
3 месяцев назад

hims sildenafil review

hims sildenafil review

trackback
3 месяцев назад

levitra vardenafil

levitra vardenafil

trackback
3 месяцев назад

levitra 10 mg filmtabletten vardenafil

levitra 10 mg filmtabletten vardenafil

trackback
3 месяцев назад

sildenafil before and after

sildenafil before and after

trackback
3 месяцев назад

cialis blood pressure side effects

cialis blood pressure side effects

trackback
3 месяцев назад

sildenafil over the counter cvs

sildenafil over the counter cvs

trackback
3 месяцев назад

ribavirin online pharmacy

ribavirin online pharmacy

trackback
3 месяцев назад

cheapest online pharmacy india

cheapest online pharmacy india

trackback
3 месяцев назад

sildenafil vs tadalafil which is better

sildenafil vs tadalafil which is better

trackback
3 месяцев назад

erectile dysfunction medications

erectile dysfunction medications

trackback

what is the difference between tadalafil and sildenafil

what is the difference between tadalafil and sildenafil

trackback
3 месяцев назад

carbamazepine and children

carbamazepine and children

trackback
3 месяцев назад

is celebrex an opioid

is celebrex an opioid

trackback
3 месяцев назад

tegretol and magnesium deficiency

tegretol and magnesium deficiency

trackback
3 месяцев назад

taking motrin and excedrin together

taking motrin and excedrin together

trackback
2 месяцев назад

elavil imitrex

elavil imitrex

trackback
2 месяцев назад

cilostazol in renal failure

cilostazol in renal failure

trackback
2 месяцев назад

indomethacin medicines.ie

indomethacin medicines.ie

trackback
2 месяцев назад

mestinon overdose in dogs

mestinon overdose in dogs

trackback
2 месяцев назад

can you get high off elavil

can you get high off elavil

trackback
2 месяцев назад

what is diclofenac sodium gel used for

what is diclofenac sodium gel used for

trackback
2 месяцев назад

can you take meloxicam and lyrica together

can you take meloxicam and lyrica together

trackback
2 месяцев назад

azathioprine for celiac disease

azathioprine for celiac disease

trackback
2 месяцев назад

maxalt copay assistance card

maxalt copay assistance card

trackback
2 месяцев назад

lioresal strengths

lioresal strengths

trackback
2 месяцев назад

piroxicam prati donaduzzi

piroxicam prati donaduzzi

trackback
2 месяцев назад

allergic reaction to sumatriptan

allergic reaction to sumatriptan

trackback
2 месяцев назад

what do periactin tablets do

what do periactin tablets do

trackback
2 месяцев назад

is flexeril or tizanidine stronger

is flexeril or tizanidine stronger

trackback
2 месяцев назад

artane beaumont community centre

artane beaumont community centre

trackback
2 месяцев назад

cyproheptadine for akathisia

cyproheptadine for akathisia

trackback
2 месяцев назад

is zanaflex good

is zanaflex good

trackback
2 месяцев назад

anatoliy-alekseyevich-derkach.ru

anatoliy-alekseyevich-derkach.ru

GenIPTV Provider
1 месяц назад

The Best Premium IPTV Service WorldWide!

trackback
1 месяц назад

dilts.g-u.su

dilts.g-u.su

Saul Best
1 месяц назад

Thanks for the sensible critique. Me and my neighbor were just preparing to do some research on this. We got a grab a book from our area library but I think I learned more from this post. I’m very glad to see such fantastic information being shared freely out there.

우리카지노더킹
1 месяц назад

I like what you guys are up also. Such intelligent work and reporting! Keep up the excellent works guys I have incorporated you guys to my blogroll. I think it’ll improve the value of my web site :).

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