context
para nos ajudar a gerenciar processos de longa duração.Server
(servidor) recebe uma Store
(armazenamento) e nos retorna um http.HandlerFunc
. Store está definida como:Fetch
(busca) da Store
para obter os dados e escrevê-los na resposta.Store
que usamos em um teste.Store
não consiga finalizar o Fetch
antes que o usuário cancele a requisição.Store
para cancelar o trabalho, então atualize a interface.data
e uma maneira de saber que foi dito para cancelar. Nós também o renomearemos para SpyStore
, pois agora vamos observar a forma como ele é chamado. Ele terá que adicionar Cancel
como um método para implementar a interface Store
.O pacote context fornece funções para derivar novos valores de contexto dos já existentes. Estes valores formam uma árvore: quando um contexto é cancelado, todos os contextos derivados dele também são cancelados.
cancellingCtx
da nossa requisição que nos retorna uma função cancel
. Nós então programamos que a função seja chamada em 5 milissegundos usando time.AfterFunc
. Por fim, usamos este novo contexto em nossa requisição chamando request.WithContext
.Store
antes do fetch em cada requisição.context
tem um método Done()
que retorna um canal que recebe um sinal quando o context estiver "done" (finalizado) ou "cancelled" (cancelado). Queremos ouvir esse sinal e chamar store.Cancel
se o obtivermos, mas queremos ignorá-lo se a nossa Store
conseguir finalizar o Fetch
antes dele.Fetch
em uma goroutine e ele irá escrever o resultado em um novo channel data
. Nós então usamos select
para efetivamente correr para os dois processos assíncronos e então escrevemos uma resposta ou cancelamos com Cancel
.*testing.T
ao criar o spy.Store
? E se a Store
também depender de outros processos de execução lenta? Nós teremos que ter certeza que a Store.Cancel
propagará corretamente o cancelamento para todos os seus dependentes.context
é que é uma maneira consistente de oferecer cancelamento.As requisições de entrada para um servidor devem criar um Context e as chamadas de saída para servidores devem aceitar um Context. A cadeia de chamadas de função entre eles deve propagar o Context, substituindo-o opcionalmente por um Context derivado criado usando WithCancel, WithDeadline, WithTimeout ou WithValue. Quando um Context é cancelado, todos os Contexts derivados dele também são cancelados.
Na Google, exigimos que os programadores Go passem um parâmetro Context como o primeiro argumento para cada função no caminho de chamada entre requisições de entrada e saída. Isto permite que o código Go desenvolvido por muitas equipes diferentes interopere bem. Ele fornece um controle simples sobre timeouts e cancelamentos e garante que valores críticos, como credenciais de segurança, transitem corretamente pelos programas Go.
context
para nossa Store
e deixá-la ser responsável. Dessa maneira, ela também pode passar o context
para os seus dependentes e eles também podem ser responsáveis por se pararem.Store
em cascata (downstream) e que trata o erro que virá da Store
quando é cancelada.Store
para mostrar as novas responsabilidades.SpyStore
:context
.data
. A goroutine escuta o ctx.Done
e irá parar o trabalho se um sinal for enviado nesse channel.select
para esperar que a goroutine termine seu trabalho ou que o cancelamento ocorra.context
, por isso certifique-se de que está entendendo o que está acontecendo.ctx
dos campos do SpyStore
porque não é mais interessante para nós. Estamos estritamente testando o comportamento agora, que preferimos em comparação aos detalhes da implementação dos testes, como "você passou um determinado valor para a função foo
".httptest.ResponseRecorder
não tem uma maneira de descobrir isso, então teremos que usar nosso próprio spy para testar.SpyResponseWriter
implementa http.ResponseWriter
para que possamos usá-lo no teste.context
e confia nas funções em cascata (downstream) para respeitar qualquer cancelamento que possa ocorrer.context
e o usa para se cancelar usando goroutines, select
e canais.http.ResponseWriter
se você precisar dele.Se você usar o ctx.Value na minha empresa (inexistente), você está demitido
context
porque parece conveniente.context.Values
é que ele é apenas um mapa não tipado para que você não tenha nenhum tipo de segurança e você tem que lidar com ele não realmente contendo seu valor. Você tem que criar um acoplamento de chaves de mapa de um módulo para outro e se alguém muda alguma coisa começar a quebrar.context.Value
. Isto torna-o estaticamente verificado e documentado para que todos o vejam.O conteúdo do context.Value é para os mantenedores e não para os usuários. Ele nunca deve ser uma entrada necessária para resultados documentados ou esperados.
context
em toda parte é um indicador que está apontando a uma deficiência na linguagem a respeito do cancelamento. Ele diz que seria melhor se isso fosse resolvido de alguma forma no nível de linguagem, em vez de em um nível de biblioteca. Até que isso aconteça, você precisará do context
se quiser gerenciar processos de longa duração.