2013-03-14 4 views
77

Я бегу Колба/Gunicorn Python приложение на Хероку Кедр дино. Приложение возвращает JSON responses своим клиентам (это действительно API server).Heroku усекает HTTP-ответы?

Время от времени клиенты получают 0-байтные ответы. Однако я не возвращаю их. Вот отрывок из журнала моего приложения:

14 марта 13:13:31 d.0b1adf0a-0597-4f5c-8901-dfe7cda9bce0 приложение [web.1] [2013-03-14 13:13: 31 UTC] 10.104.41.136 apisrv - api_get_credits_balance(): session_token = [MASKED]

Первая строка выше меня начинает обрабатывать запрос.

14 марта 13:13:31 d.0b1adf0a-0597-4f5c-8901-dfe7cda9bce0 приложение [web.1] [2013-03-14 13:13:31 UTC] 10.104.41.136 apisrv 1252148511 api_get_credits_balance(): возвращение [{ 'credits_balance': 0}]

Вторая строка мне возвращает значение (для Колбы - это колба "Response" объект).

Mar 14 13:13:31 d.0b1adf0a-0597-4f5c-8901-dfe7cda9bce0 приложение [web.1] «10.104.41.136 - - [14/Mar/2013: 13: 13: 31] "? ПОСТ /get_credits_balance session_token = MASKED HTTP/1.1" 200 22 "-" "Appcelerator титана/3.0.0.GA (iPhone/6.1.2; iPhone OS; en_US;)"

третьего линия - это Gnicorn's, где вы можете видеть, что Gunicorn получил статус 200 и 22 байта HTTP-объекта («200 22»).

Однако клиент получил 0 байт. ю Heroku журнала маршрутизатора:

14 марта 13:13:30 d.0b1adf0a-0597-4f5c-8901-dfe7cda9bce0 Heroku [маршрутизатор] при = Информация = метод POST путь =/get_credits_balance session_token = MASKED ? хозяйничать = matchspot-apisrv.herokuapp.com FWD = "66.87.116.128" Dyno = web.1 очереди = 0 ожидания = 0ms подключающиеся = 1мс сервис = 19ms статус = 200 байт = 0

Почему Gunicorn возвращение 22 байта, но Heroku видит 0 и действительно передает обратно 0 байтам клиенту? Это ошибка Героку?

+1

Вы заметили, что героическая метка времени находится перед вашей временной отметкой? Вы используете gevent? Я думаю, что-то не так с синхронизацией. – Tigra

+0

Спасибо, что комментировали. Я использую обычных сотрудников-манипуляторов Gunicorn, а не gevent или любую другую родословную. Интересное наблюдение относительно метки времени, но моя гипотеза будет заключаться в том, что временная метка, написанная Heroku, является меткой времени, когда маршрутизатор * получил * запрос. Просто догадка. Это объясняет разницу в 1сек в метках времени (реальная разница, конечно, может составлять 1 мс, 1 мс, которая скатывается по второму счету от 30 до 31). На этом этапе я должен добавить, что после публикации этого вопроса я включил новую функцию Heroku-labs, которая печатает уникальный «идентификатор запроса» в журналах маршрутизатора Herkou (продолж.) –

+0

(продолжение) и передает это как HTTP-заголовок для моего работника, поэтому я могу сопоставить строки. Линии * do * коррелируют, когда происходят явления. Кроме того, я добавил крюк post-request для пушки, который печатает ответ, и, действительно, gunicorn утверждает, что написал и сбросил все байты ответа. –

ответ

1

Я знаю, что меня можно считать немного от стены, но есть другой вариант.

Мы знаем, что время от времени возникает ошибка, которая происходит при транзите. Мы знаем, что мы не можем сейчас сделать, чтобы остановить проблему. Если вы предоставляете API только тогда, прекратите читать, если вы тоже напишите клиент, продолжайте движение.

Ошибка - это известный случай и известная причина. Результат пустого возвращаемого значения означает, что что-то пошло не так. Однако значение доступно и было выбрано, вычислено, независимо от того ... Мой инстинкт как разработчик должен обрабатывать пустой результат как ошибку HTTP и запрашивать, чтобы данные были повторно отправлены. Затем вы можете отслеживать повторные запросы и посмотреть, как часто это происходит.

Я бы предложил (хотя вы напомнили мне, что разработчик тоже подумал об этом), что вы подсчитываете запросы и устанавливаете разумное значение для ответа «сетевой ошибки» на пользователя. Моим инстинктом было бы сразу повторить попытку, а затем немного подождать, прежде чем повторить попытку.

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

Это также будет маршрутизировать любое количество других сетевых ошибок в сети «точка-точка» и оставить приложение более надежным даже перед лицом проблем с подключением.

Я знаю, что наш инстинкт, как разработчики, должен исправить известную ошибку, но иногда лучше работать с системой, способной работать, несмотря на неисправности. Тем не менее, никогда не мешает регистрировать ошибки и проблемы и пытаться их исправить.

+0

На самом деле это не плохой комментарий (хотя, вероятно, должен быть в комментарии, а не в ответе), и не думаю, что я об этом не думал ... Проблема в том, что клиент не может снова отправить запрос , потому что запрос может иметь побочные эффекты на стороне сервера (например, переводить деньги во второй раз, скажем). Решение для этого заключается в том, чтобы клиент выдавал request_id, а для сервера - список «who request_id», который был отправлен за последние 60 секунд. Когда клиент получает ответ 200 с телом 0 байтов, он повторно отправляет запрос с тем же идентификатором, и сервер не выполняет повторное выполнение (con't) –

+0

(продолжение) все это снова. Однако это так уродливо, что я решил не реализовывать. –

+0

Я едва начинаю при кешировании, но мне кажется: отправьте случайную строку как часть запроса и кешируйте результат. При повторной отправке запроса с той же случайной строкой вы, естественно, получите кешированный результат (тот же контент, тот же источник ...), но когда вы отправляете новый новый запрос, у вас есть новая случайная строка и, таким образом, не кэшируется результат. – Narfanator

Смежные вопросы