7. ТЕСТИРОВАНИЕ
И КОД-РЕВЬЮ
Чем раньше найдена ошибка — тем она дешевле
Тесты — для продуманных заранее краевых случаев,
код-ревью — для возможно пропущенных
Unit-тесты не отменяют приемочных
16. ЛОГИ
Processing GET "/requests/10" for 1.1.1.1
Completed 200 OK in 336ms (Views: 0.8ms | ActiveRecord: 12.9ms)
Когда был сделан запрос?
Как получить все логи по запросу?
Были ли запросы во внешние API и если были —
то какие ответы были получены?
Для какого пользователя запрос?
17. ЛОГИ
[2015-04-18 20:11:39] [7d1fe7a2] [user_id=42] Processing GET "/requests/10" for 1.1.1.1
[2015-04-18 20:11:39] [7d1fe7a2] [user_id=42] PartnerApi request:
http://example.com/?param=value
[2015-04-18 20:11:39] [7d1fe7a2] [user_id=42] PartnerApi response: 403 Forbidden
[2015-04-18 20:11:39] [7d1fe7a2] Completed 200 OK in 336ms (Views: 0.8ms |
ActiveRecord: 12.9ms)
+ консолидация логов (logstash или скрипты)
19. АСИНХРОННОСТЬ
def process_request(params)
resp = HttpRequest.perform(params_for(request))
data = ResponseParser.parse(resp)
DataProcessor.process(data)
end
requests.each {|r| process_request(r)}
20. АСИНХРОННОСТЬ — ЗЛО
def process_request(request)
AsyncHttpRequest.perform(params_for(request)) do |resp|
AsyncResponseParser.parse(resp) do |data|
AsyncDataProcessor.process(data)
end
end
end
requests.each {|r| process_request(r)}
22. АСИНХРОННОСТЬ — ЗЛО
Код менее читаемый
Все библиотеки должны знать про асинхронность
Все ошибки должны корректно обрабатываться
(т.к. общее состояние)
31. ДЕЙСТВИЯ ПРИ ЧП!
НЕ ПАНИКОВАТЬ, НЕ ВЫКАТЫВАТЬ ХАОТИЧЕСКИЕ
«ХОТФИКСЫ»
СОБРАТЬ КАК МОЖНО БОЛЬШЕ ИНФЫ
НЕ СТЕСНЯТЬСЯ СПРАШИВАТЬ ИДЕЙ У КОЛЛЕГ
ГУГЛИТЬ
ИСКАТЬ И ИСПРАВЛЯТЬ ПРИЧИНУ, А НЕ СЛЕДСТВИЕ
41. ПРОБЛЕМА 1
Причина: strace — подвисли на запросе к API
без API можно обработать 85% запросов
Решение: мониторим состояние API и если все плохо —
просто не делаем запросов
45. ПРОБЛЕМА 2
Причина: Длинные транзакции в sidekiq воркерах
Превышение лимита одновременных транзакций
Решение: Делаем в транзакции только самое
необходимое, остальное — вне транзакции.
50. АНАЛИЗ СИТУАЦИИ
def fill_location(loc)
if loc
self.coords_source = loc.source
self.coords = loc.coords
fill_address_if_required
end
self.state = 'processed'
save! # ← зависает тут
end