Sobes.tech
Junior

O que é o contexto em Go?

sobes.tech IA

Resposta da IA

O contexto (context.Context) em Go é um objeto que transporta um prazo limite, um sinal de cancelamento e dados específicos da solicitação. É usado para gerenciar o ciclo de vida das goroutines e para transmitir informações entre elas durante a execução de uma solicitação/operação.

Características principais:

  • Seguro para concorrência: Pode ser transferido com segurança entre goroutines.
  • Imutável: Uma vez criado, um Context não pode ser alterado. Os contextos derivados são criados a partir do pai.
  • Hierárquico: Os contextos formam uma árvore com raiz (context.Background() ou context.TODO()). O cancelamento do contexto pai leva ao cancelamento de todos os seus filhos.

Funções principais do pacote context:

  • context.Background() : Contexto vazio, geralmente usado na função main, em solicitações de alto nível ou em testes. Nunca é cancelado.
  • context.TODO() : Também um contexto vazio. Usado como marcador de posição quando não se sabe qual contexto usar, ou se a funcionalidade do contexto ainda não foi implementada.
  • context.WithCancel(parent Context) : Retorna um novo contexto filho e uma função de cancelamento. Chamar essa função cancela este contexto e todos os seus contextos filhos.
  • context.WithDeadline(parent Context, deadline time.Time) : Retorna um contexto filho que é automaticamente cancelado quando o tempo especificado chega. Também retorna uma função de cancelamento para cancelamento manual.
  • context.WithTimeout(parent Context, timeout time.Duration) : Igual a WithDeadline, mas especificando uma duração.
  • context.WithValue(parent Context, key, val interface{}) : Retorna um contexto filho com um valor associado a uma chave.

Aplicações:

  • Cancelar operações: Por exemplo, um timeout em uma requisição HTTP ou a interrupção de uma operação prolongada.
  • Transmissão de dados: Por exemplo, ID de requisição para registro, informações de autenticação.

Exemplo de uso de context.WithTimeout:

package main

import (
	"context"
	"fmt"
	"time"
)

func longRunningOperation(ctx context.Context, resultChan chan string) {
	select {
	case <-time.After(3 * time.Second):
		// Operação concluída com sucesso
		resultChan <- "Operação concluída"
	case <-ctx.Done():
		// O contexto foi cancelado
		err := ctx.Err() // Obtemos a causa do cancelamento
		resultChan <- fmt.Sprintf("Operação cancelada: %v", err)
	}
}

func main() {
	// Cria um contexto com timeout de 2 segundos
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel() // Garantir chamada de cancel

	resultChan := make(chan string, 1)

	go longRunningOperation(ctx, resultChan)

	// Espera pelo resultado ou cancelamento
	select {
	case res := <-resultChan:
		fmt.Println(res)
	case <-ctx.Done():
		fmt.Printf("Context principal terminado: %v\n", ctx.Err())
	}

	// Espera um pouco para que a goroutine termine, se foi cancelada
	time.Sleep(1 * time.Second)
}

Neste exemplo, longRunningOperation verifica se o contexto foi cancelado. Se o timeout do contexto principal (2 segundos) expirar antes que a operação termine (3 segundos), a goroutine recebe o sinal de cancelamento através de ctx.Done() e termina.