contextvars.Token: restaure contexto async

Publicado em: 14/10/2026
Tempo de leitura: 6 minutos
Código Python representando contextvars.Token e isolamento de contexto assíncrono

contextvars.Token representa a alteração produzida quando um valor é definido em uma ContextVar. A partir do Python 3.14, o token também pode ser usado como gerenciador de contexto, permitindo definir um valor temporário com with e restaurar automaticamente o estado anterior ao sair do bloco. Isso simplifica código assíncrono, middleware, logs estruturados, rastreamento de requisições e qualquer situação em que dados de contexto precisam acompanhar uma execução sem depender de variáveis globais.

Variáveis de contexto foram criadas para manter informações isoladas entre tarefas concorrentes. Em aplicações com asyncio, duas corrotinas podem executar no mesmo thread e ainda assim enxergar valores diferentes para a mesma ContextVar. O token é a peça que permite desfazer uma alteração corretamente, inclusive quando havia um valor anterior ou quando a variável ainda não tinha sido definida.

O problema das variáveis globais

Uma variável global parece suficiente para guardar um identificador de requisição, usuário atual ou código de rastreamento. Porém, quando várias requisições são executadas ao mesmo tempo, uma pode sobrescrever o valor da outra. O resultado são logs misturados, permissões incorretas e erros difíceis de reproduzir. Usar threading.local() também não resolve completamente em servidores assíncronos, porque várias tarefas compartilham o mesmo thread.

ContextVar resolve esse problema associando o valor ao contexto de execução. O Python copia e propaga esse contexto de forma apropriada quando novas tarefas são criadas. Isso torna o recurso especialmente útil em frameworks web assíncronos, consumidores de filas, bibliotecas de observabilidade e pipelines concorrentes.

Uso tradicional com set e reset

from contextvars import ContextVar

request_id = ContextVar("request_id", default="sem-id")

def processar():
    token = request_id.set("req-123")
    try:
        print(request_id.get())
    finally:
        request_id.reset(token)

processar()
print(request_id.get())

O método set() retorna um token. Esse token registra qual era o valor anterior e pertence exatamente à variável que foi alterada. O método reset() usa o token para restaurar o estado. O bloco finally é essencial, pois garante a restauração mesmo se ocorrer uma exceção.

Token como gerenciador de contexto

No Python 3.14, o token pode ser usado diretamente com with. A intenção fica mais clara e há menos risco de esquecer o reset().

from contextvars import ContextVar

usuario_atual = ContextVar("usuario_atual", default="anônimo")

with usuario_atual.set("leandro"):
    print(usuario_atual.get())

print(usuario_atual.get())

Dentro do bloco, o valor é leandro. Ao sair, o valor anterior é restaurado automaticamente. Essa forma é especialmente útil para escopos curtos, testes e funções de infraestrutura que precisam aplicar contexto temporário.

Valores aninhados

Os blocos podem ser aninhados. Cada token restaura exatamente o estado anterior ao seu próprio set().

nivel = ContextVar("nivel", default="info")

with nivel.set("debug"):
    print(nivel.get())
    with nivel.set("trace"):
        print(nivel.get())
    print(nivel.get())

print(nivel.get())

A sequência será debug, trace, debug e info. Essa previsibilidade evita restaurações manuais incorretas quando várias camadas alteram a mesma variável.

Exemplo com asyncio

import asyncio
from contextvars import ContextVar

correlation_id = ContextVar("correlation_id", default="-")

async def worker(nome):
    with correlation_id.set(f"job-{nome}"):
        await asyncio.sleep(0.01)
        print(nome, correlation_id.get())

async def main():
    await asyncio.gather(worker("A"), worker("B"))

asyncio.run(main())

Mesmo com as duas tarefas intercaladas, cada uma preserva seu próprio identificador. Não é necessário passar o valor manualmente por todas as funções. Isso reduz acoplamento, mas não significa que toda informação deve virar uma ContextVar. Dados importantes do domínio ainda devem aparecer explicitamente nas interfaces quando isso melhora a clareza.

Logs estruturados

Um uso comum é incluir automaticamente um identificador em todas as mensagens de log.

import logging
from contextvars import ContextVar

request_id = ContextVar("request_id", default="-")

class ContextFilter(logging.Filter):
    def filter(self, record):
        record.request_id = request_id.get()
        return True

handler = logging.StreamHandler()
handler.addFilter(ContextFilter())
handler.setFormatter(logging.Formatter("%(request_id)s %(levelname)s %(message)s"))

logger = logging.getLogger("app")
logger.setLevel(logging.INFO)
logger.addHandler(handler)

Um middleware pode abrir um bloco com o ID da requisição e todo o código executado dentro dele recebe o valor correto. Ao final, o estado é restaurado, evitando vazamento para a próxima requisição processada pelo mesmo worker.

Middleware e tratamento de exceções

O gerenciador de contexto reduz código repetitivo em middleware. Mesmo que a função chamada lance uma exceção, a saída do bloco restaura o valor anterior.

async def middleware(handler, requisicao):
    identificador = requisicao.headers.get("X-Request-ID", "gerado-localmente")
    with request_id.set(identificador):
        return await handler(requisicao)

A restauração automática é importante porque exceções, cancelamentos e retornos antecipados fazem parte do fluxo normal de servidores assíncronos.

Cuidados com tokens

Um token deve ser usado apenas com a variável que o criou. Também não deve ser reutilizado depois de uma restauração. O Python rejeita usos inválidos para impedir corrupção silenciosa do contexto. Guarde o token somente pelo tempo necessário e prefira o bloco with quando o escopo for local.

Outra regra importante é não compartilhar tokens entre tarefas. O valor da variável pode ser propagado para uma nova tarefa, mas o token está ligado à alteração e ao contexto onde foi produzido.

Token.MISSING

Quando a variável não possuía valor antes do set(), a propriedade old_value do token pode conter Token.MISSING. Isso é diferente de um valor explícito igual a None. A distinção permite restaurar corretamente o estado de uma variável sem valor definido.

from contextvars import ContextVar, Token

chave = ContextVar("chave")
token = chave.set(None)

if token.old_value is Token.MISSING:
    print("não existia valor anterior")

chave.reset(token)

Compatibilidade entre versões

O uso do token como gerenciador de contexto depende do Python 3.14 ou posterior. Bibliotecas que ainda suportam versões anteriores devem manter a forma com set(), try, finally e reset(), ou criar uma função auxiliar compatível.

from contextlib import contextmanager

@contextmanager
def valor_temporario(var, valor):
    token = var.set(valor)
    try:
        yield
    finally:
        var.reset(token)

Essa abstração oferece uma interface semelhante em versões antigas e pode ser removida quando o projeto adotar Python 3.14 como mínimo.

Testes automatizados

Contextos temporários ajudam a manter testes independentes. Cada teste pode definir o usuário, idioma ou identificador necessário sem alterar estado global permanente.

def test_contexto_temporario():
    idioma = ContextVar("idioma", default="pt")

    with idioma.set("en"):
        assert idioma.get() == "en"

    assert idioma.get() == "pt"

Também vale testar exceções para confirmar que o valor é restaurado. Em suítes assíncronas, crie tarefas concorrentes com valores diferentes e valide que não existe contaminação entre elas.

Desempenho e arquitetura

ContextVar foi projetada para operações frequentes, mas ainda adiciona uma camada de indireção. Não use o recurso para substituir todos os parâmetros de função. Ele funciona melhor para dados transversais, como rastreamento, contexto de segurança, localização e telemetria. Informações centrais da regra de negócio devem continuar explícitas quando possível.

Em bibliotecas, documente quais variáveis são lidas e quem é responsável por defini-las. Forneça valores padrão seguros e evite falhar com mensagens obscuras quando o contexto não estiver disponível.

Boas práticas

Defina as ContextVar no nível do módulo, use nomes descritivos, escolha defaults seguros, limite o escopo das alterações e restaure sempre o estado. Prefira with var.set(valor) em Python 3.14 e use try/finally em versões anteriores. Não coloque objetos mutáveis compartilhados no contexto sem entender as consequências: a variável isola a referência, mas não transforma o objeto em imutável.

Para aprofundar conceitos relacionados, veja os artigos da Academify sobre programação assíncrona com asyncio, logging no Python, gerenciadores de contexto e threads no Python. Consulte também a documentação oficial de contextvars e a referência oficial do comando with.

Conclusão

O suporte de contextvars.Token ao protocolo de gerenciador de contexto torna alterações temporárias mais legíveis e seguras. Ele elimina código manual de restauração, funciona bem com exceções e preserva o isolamento entre tarefas assíncronas. Em aplicações modernas, isso facilita logs correlacionados, middleware, testes e telemetria sem recorrer a globais frágeis. A principal decisão arquitetural é usar contexto somente para informações transversais e manter os dados essenciais do domínio explícitos.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Visualização de dados e distribuição estatística para statistics.kde_random no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    statistics.kde_random: gere amostras de uma KDE

    Aprenda statistics.kde_random no Python para gerar amostras a partir de uma distribuição estimada por kernel com controle de suavização, sementes

    Ler mais

    Tempo de leitura: 6 minutos
    13/10/2026
    Ambiente Linux representando namespaces e automação com os.setns no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    os.setns: entre em namespaces Linux com segurança

    Aprenda os.setns no Python para mover processos entre namespaces Linux com segurança, permissões, testes e limpeza adequada.

    Ler mais

    Tempo de leitura: 5 minutos
    13/10/2026
    Computador com código representando cópia de arquivos com Path.copy no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    Path.copy: copie arquivos e pastas com segurança

    Aprenda Path.copy no Python para copiar arquivos e diretórios com controle, segurança, desempenho e compatibilidade.

    Ler mais

    Tempo de leitura: 6 minutos
    12/10/2026
    Código em monitor representando acesso a memória nativa com ctypes.memoryview_at no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    ctypes.memoryview_at: acesse memória sem cópias

    Aprenda ctypes.memoryview_at no Python para acessar memória nativa sem cópias, validar ponteiros e evitar erros perigosos.

    Ler mais

    Tempo de leitura: 7 minutos
    12/10/2026
    Código Python em tela representando EnumDict e enumerações avançadas
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    EnumDict: personalize Enums com validação

    Aprenda EnumDict no Python para personalizar EnumType, validar membros e criar enumerações avançadas com segurança.

    Ler mais

    Tempo de leitura: 5 minutos
    11/10/2026
    Rack de servidores representando balanceamento de conexões com SO_REUSEPORT_LB no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    SO_REUSEPORT_LB: distribua conexões entre workers

    Aprenda SO_REUSEPORT_LB no Python para distribuir conexões entre múltiplos workers com segurança, testes e portabilidade.

    Ler mais

    Tempo de leitura: 6 minutos
    11/10/2026