Atualizações de Apps
Atualizações de Apps
O framework Turn Apps suporta a atualização de apps para novas versões enquanto preserva estados importantes como configuração e URLs de webhook. Esta seção aborda como as atualizações funcionam e como implementar hooks de atualização no seu app.
Visão Geral
Quando você faz upload de uma nova versão de um app, a plataforma gerencia automaticamente as transições de versão:
- Arquivamento automático - Quando você faz upload de uma nova versão, a versão anterior é automaticamente arquivada
- Versão única ativa - Apenas uma versão de cada app pode estar ativa por vez por número
- Atualizar instalação existente - Se o app já estiver instalado, você pode atualizar a instalação existente para preservar o
app_install.uuid(mantendo URLs de webhook estáveis), configuração e histórico de versões
Para apps instalados, você normalmente vai querer atualizar instalações existentes para manter a continuidade para usuários que integraram as URLs de webhook do seu app em sistemas externos.
O Que é Preservado Durante a Atualização
Ao atualizar um app, o seguinte é preservado:
- UUID da Instalação do App - O identificador único desta instalação permanece o mesmo, o que significa que URLs de webhook (
/apps/{uuid}/webhook) continuam funcionando - Configuração - Todos os valores de config são preservados por padrão (apps podem migrar config via hooks de atualização)
- Histórico de Versões - O sistema rastreia até 10 versões anteriores, permitindo rollback se necessário
O Fluxo de Atualização
- Usuário faz upload da nova versão de um app existente
- Sistema detecta uma instalação existente com o mesmo nome de app
- Usuário escolhe "Atualizar instalação existente"
- Se atualizando para uma versão mais nova:
- O pool de workers atual é parado
- Histórico de versões registra a versão antiga e snapshot da config
- AppInstall é atualizado para apontar para a nova versão (config preservada)
- O evento
upgradeexecuta com acesso às APIsturn.app.*para migração de config - Um novo pool de workers inicia com o novo código
- Se fazendo downgrade para uma versão mais antiga:
- Processo similar, mas o evento
downgradeexecuta em vez disso
- Processo similar, mas o evento
Implementando Hooks de Atualização
Apps podem implementar eventos upgrade e downgrade em on_event para migrar configuração entre versões. Isso é particularmente útil quando:
- Você renomeou campos de configuração
- Você precisa transformar valores de config para a nova versão
- Você quer adicionar metadados sobre a migração
O Evento upgrade
Chamado ao atualizar DE uma versão mais antiga PARA uma versão mais nova. O hook executa no código do novo app com acesso total às APIs turn.app.*:
function App.on_event(app, number, event, data)
if event == "upgrade" then
-- data.from_version: versão de origem (ex: "1.0.0")
-- data.to_version: versão de destino (ex: "2.0.0")
turn.logger.info("Atualizando de " .. data.from_version .. " para " .. data.to_version)
-- Ler config atual usando a API turn.app
local config = turn.app.get_config()
-- Exemplo: renomear um campo na v2.0.0
if config.old_api_endpoint then
config.api_url = config.old_api_endpoint
config.old_api_endpoint = nil
end
-- Adicionar metadados de atualização
config.upgraded_from = data.from_version
config.upgraded_at = os.date("!%Y-%m-%dT%H:%M:%SZ")
-- Salvar a config migrada
turn.app.set_config(config)
return true
end
end
O Evento downgrade
Chamado ao fazer downgrade DE uma versão mais nova PARA uma versão mais antiga. O hook executa no código do app antigo (de destino) com acesso total às APIs turn.app.*:
function App.on_event(app, number, event, data)
if event == "downgrade" then
-- data.from_version: versão de origem (ex: "2.0.0")
-- data.to_version: versão de destino (ex: "1.0.0")
turn.logger.info("Fazendo downgrade de " .. data.from_version .. " para " .. data.to_version)
-- Ler config atual usando a API turn.app
local config = turn.app.get_config()
-- Reverter a renomeação de campo da v2.0.0
if config.api_url then
config.old_api_endpoint = config.api_url
config.api_url = nil
end
config.downgraded_from = data.from_version
-- Salvar a config migrada
turn.app.set_config(config)
return true
end
end
Apps Sem Hooks de Atualização
Se seu app não implementa hooks de upgrade/downgrade, a configuração existente é preservada como está durante as atualizações. Este é o comportamento padrão e funciona bem para apps onde a estrutura da config não muda entre versões.
Histórico de Versões e Rollback
A plataforma mantém um histórico de versões para cada instalação de app, registrando:
- String de versão - A versão semântica (ex: "1.0.0")
- UUID da definição do app - Referência à definição do app
- Atualizado em - Timestamp ISO 8601 de quando a atualização ocorreu
- Snapshot de config - A configuração completa no momento da atualização
Este histórico é limitado a 10 entradas por padrão para evitar crescimento ilimitado.
Capacidade de Rollback
Usuários podem fazer rollback para a versão anterior a partir da página de configurações do app. Ao fazer rollback:
- O sistema recupera a definição do app anterior do histórico de versões
- O snapshot de config daquela versão é restaurado
- O hook de downgrade executa no código da versão anterior (se implementado)
- O pool de workers reinicia com a versão anterior
Isso fornece uma rede de segurança quando atualizações causam problemas inesperados.
Rollback Automático em Caso de Falha
O processo de atualização inclui rollback automático para garantir a estabilidade do app. Se qualquer um dos seguintes ocorrer durante a atualização:
- Hook de upgrade retorna
false- O manipulador do eventoupgradedo app indica falha - Pool falha ao iniciar - O novo código do app falha ao inicializar
A plataforma irá automaticamente:
- Restaurar a definição do app anterior
- Restaurar o snapshot de config de antes da atualização
- Remover a entrada do histórico de versões que acabou de ser adicionada
- Reiniciar o pool de workers com a versão anterior
- Retornar uma mensagem de erro explicando o que aconteceu
Isso garante que os apps permaneçam funcionais mesmo quando atualizações falham. O rollback automático preserva:
- A versão e código original do app
- Todos os valores de configuração de antes da tentativa de atualização
- Funcionalidade completa (o pool reinicia com a versão funcionando)
Exemplo de tratamento de falhas de atualização:
function App.on_event(app, number, event, data)
if event == "upgrade" then
-- Validar que serviços externos necessários estão disponíveis
local ok, err = validate_external_dependencies()
if not ok then
turn.logger.error("Atualização falhou: " .. err)
-- Retornar false dispara o rollback automático
return false
end
-- Prosseguir com a migração de config
local config = turn.app.get_config()
-- ... lógica de migração ...
turn.app.set_config(config)
return true
end
end
Melhores Práticas para Atualizações
-
Sempre Teste Caminhos de Atualização - Antes de lançar uma nova versão, teste a atualização a partir da versão anterior
-
Faça Hooks de Atualização Idempotentes - Se um hook de atualização executar múltiplas vezes, deve produzir o mesmo resultado
-
Lide com Campos Ausentes Graciosamente - Não assuma que campos existem; use valores padrão:
local timeout = migrated_config.timeout or 30 -
Registre Ações de Atualização - Ajude os usuários a entender o que mudou durante a atualização:
turn.logger.info("Migrado api_endpoint para api_url") -
Documente Mudanças Importantes - Use
get_app_info_markdownpara comunicar mudanças de versão:elseif event == "get_app_info_markdown" then
return [[
# Meu App v2.0
## Notas de Atualização
- Campo de config `api_endpoint` foi renomeado para `api_url`
- O hook de atualização migra isso automaticamente para você
]]
end -
Preserve Versionamento Semântico - Use semver apropriado para comunicar o tipo de mudanças:
- MAJOR: Mudanças incompatíveis requerendo migração de config
- MINOR: Novas funcionalidades, compatíveis com versões anteriores
- PATCH: Correções de bugs