Ответ 1
Одной из наиболее распространенных потребностей в передаче контекста является корреляция исходящих запросов к входящим запросам. Я использовал это для различных целей, например:
- Я хочу, чтобы журналы ошибок для моего компонента базы данных включали полный URL-адрес из запроса http, это результат.
- Входящие HTTP-запросы содержат набор заголовков, которые мне нужно сохранить и передать другим службам http, которые я вызываю downstream (возможно, для отслеживания причин).
- Я хочу проверить входящий HTTP-запрос в каком-либо другом компоненте, чтобы выполнить контроль доступа или аутентификацию пользователя или что-то еще. Это может быть на уровне обработчика http или какой-либо другой части моего приложения.
Многие языки и платформы имеют удобные/магические способы получения текущего запроса Http. С# имеет HttpRequest.Current
, который доступен по всему миру (через локальное хранилище потоков) всем, кто хочет узнать контекст текущего HTTP-запроса. Вы можете установить на нем произвольные данные для передачи различных контекстных данных. Другие платформы имеют аналогичные возможности.
Так как go не имеет средств для локального хранилища goroutine, невозможно сохранить глобальную переменную в контексте текущего HTTP-запроса. Вместо этого, идиоматично инициализировать контекст на границе вашей системы (входящий запрос) и передавать его в качестве аргумента для любых нисходящих компонентов, которым необходим доступ к этой информации.
Один из самых простых способов сделать это - сделать объект контекста с текущим HTTP-запросом и передать его:
func someHandler(w http.ResponseWriter, r * http.Request){
ctx := context.WithValue(context.Background(),"request",r)
myDatabase.doSomething(ctx,....)
}
Конечно, вы можете ограничить его более целенаправленным набором данных, которые вам нужно передать, а не весь запрос.
Другое, что помогает пакет контекста (и я думаю, что блог делает хорошую работу по указанию), является общей основой для тайм-аутов или сроков.
Обратите внимание, что пакет контекста не использует тайм-ауты для вас. Это зависит от компонентов, получающих объект контекста, чтобы наблюдать за Done-каналом и самостоятельно отменить свой собственный запрос HTTP или вызов или расчет базы данных или что-то еще.
edit - on timeouts
Очень полезно иметь возможность управлять тайм-аутами извне компонента. Если у меня есть модуль базы данных, мне не нужно фиксировать значения тайм-аута, просто уметь обрабатывать тайм-аут, запускаемый извне.
Один из способов, которым я это сделал, - это служба, которая делает несколько вызовов db/service на входящий запрос. Если общее время превышает 1 секунду, я хочу прервать все исходящие операции и вернуть результат частичного или ошибки. Инициализация контекста с тайм-аутом на верхнем уровне и передача его во все зависимости - это действительно простой способ управления этим.
Не всегда приятно, чтобы зависимость слушала канал Done и прерывала его работу, но, как показывает блог, это тоже не очень больно.