Desenvolvimento

5 set, 2017

Desenvolvendo aplicativos mais confiáveis com XP Background Push da engenharia da Uber

Publicidade

Ao contrário da programação do lado do servidor, o código de celular não pode ser retraído uma vez que ele já foi enviado e só pode ser atualizado quando o usuário optar por uma atualização do aplicativo. Para a Engenharia da Uber, isso apresenta desafios únicos quando se trata de lançar novos recursos de forma incremental, de corrigir erros e de reduzir as interrupções em escala em nossos aplicativos móveis.

A Experimentation Platform (XP) da Uber é responsável por garantir que os novos recursos móveis se desenvolvam de forma tão perfeita quanto possível para nossos usuários. Em seu modo de operação normal, a XP permite que um aplicativo móvel consulte um serviço de back-end (Serviço de Tratamento) para recuperar um conjunto de recursos (sinalizadores) que devem ser ativados para um determinado usuário. No entanto, isso se torna problemático – e gera erros! – quando o estado dos sinalizadores é consultado no código antes que a carga útil do XP seja retornada ao aplicativo.

Para combater esses desafios, desenvolvemos a XP Background Push para mitigar erros de forma segura e eficiente em tempo real. Ao contrário dos modelos tradicionais baseados em pull, nossa ferramenta baseada em push nos permite forçar proativamente o aplicativo de um usuário a uma determinada configuração sem ter que esperar que o aplicativo chame por um serviço back-end e retorne a carga útil, tornando mais fácil e rápido consertar erros na escala Uber.

Neste artigo, discutimos como esta nova poderosa ferramenta permite aos nossos engenheiros implantar aplicativos mais confiáveis ​​para nossos usuários alavancando os serviços existentes da Uber.

Corrigindo erros antes da XP Background Push

Sem a XP Background Push, era difícil ter certeza absoluta de que poderíamos retornar os usuários para um estado de trabalho no caso de um erro principal estar atrás de um sinalizador de recurso.

Considere o seguinte cenário teórico como exemplo: a Uber lança um novo recurso no App v1 e posteriormente descobrimos que, para alguns usuários, o recurso causa uma falha que os impede de solicitar uma corrida. Nós, imediatamente, incorporamos uma correção para esse erro no App v2, mas levará tempo para carregar v2 no App ou nas Lojas do Google Play. Além disso, mesmo que a nova versão esteja disponível para download, os usuários devem, voluntariamente, atualizar a versão recomendada e somente usuários que voluntariamente baixaram o App v2 incorporaram a correção.

Idealmente, seríamos capazes de reverter o recurso quebrado no v1 dinamicamente através da nossa XP para que os usuários voltem a um estado de trabalho até que eles atualizem para o v2 remendado. Nesse cenário, os novos recursos estão escondidos por trás dos sinalizadores dos recursos e o estado desses sinalizadores é consultado no nosso Serviço de Tratamento, um serviço de back-end que decide qual “tratamento” mostrar a um usuário. O Serviço de Tratamento nos permite controlar o lançamento do lado do servidor e reverter os recursos com erro simplesmente desabilitando um sinalizador.

Esse tipo de controle do lado do servidor é extremamente poderoso e funciona, na maioria das vezes. No entanto, ainda existem alguns casos excepcionais que não podem ser manipulados com a tradicional sinalização de recursos, por exemplo, quando o código por trás de um sinalizador ocorre antes que a carga útil da configuração seja retornada. Isso é importante para a Uber porque, para garantir que os tempos de carregamento do aplicativo sejam rápidos e sem problemas, os sinalizadores são obtidos de forma assíncrona. Em outras palavras, preferimos usar apenas APIs que não bloqueiam o uso da UI no aplicativo.

Considere um cenário que ocorre quando a solicitação de experimentos não é bloqueadora: um recurso com erro que é fechado por um sinalizador é enviado e o sinalizador é verificado no aplicativo antes que a carga útil do Serviço de Tratamento seja retornada. Este sinalizador está ativado para algum subconjunto da população no Serviço de Tratamento, mas no primeiro lançamento, o sinalizador será desativado uma vez que a carga útil não chegou. Quando a carga útil chega, ela é armazenada em cache para lançamentos subsequentes. O código por trás do sinalizador começa a causar falhas e, portanto, o sinalizador é, em seguida, desabilitado no Serviço de Tratamento. No entanto, o sinalizador não pode ser desativado porque está marcado antes da chegada da carga útil e a falha ocorre antes que a carga útil (contendo as informações necessárias para desativar o sinalizador) seja recebida.

Esta situação está longe de ser ideal e pode afetar a experiência da Uber para nossos usuários. Felizmente, com a XP Background Push, erros como estes podem ser mitigados com a pressão de seus dedos – ou melhor, a entrega de uma notificação push.

Usando notificações push para corrigir erros

Para corrigir erros e resolver falhas nesses tipos de cenários, nossa XP Background Push usa notificações push silenciosas para ativar ou desativar sinalizadores de recursos. Se houver um bug que precisa ser corrigido, enviamos uma notificação de push silenciosa que contém uma carga útil que instrui o aplicativo para ativar ou desativar um recurso, mitigando o desempenho fraco do aplicativo até o problema ser resolvido em uma versão futura.

Isso parece bastante simples em teoria, mas realmente requer uma interação deliberada e inteligente entre os serviços para executar corretamente. O envio de notificações push para um grande número de usuários leva tempo e adiciona estresse na nossa infraestrutura. Portanto, enviar notificações a todos os usuários em caso de interrupção não é viável nem eficiente.

Assim, o primeiro e mais complicado problema é determinar quais usuários são afetados por um bug e, portanto, notificações precisam ser enviadas. Uma vez que o Serviço de Tratamento é responsável por avaliar o status do sinalizador e enviá-lo para clientes móveis, ele pode determinar quais sinalizadores estão habilitados no dispositivo de um usuário específico, ou inversamente, em quais dispositivos de usuários um sinalizador em particular está ativado.

Fluxo de trabalho da XP Background Push

No nosso fluxo de trabalho de background push, um envio é desencadeado por um desenvolvedor através de uma interface web. Isso envia uma carga útil e uma chave Cassandra para GroupPusher, que puxa a lista de usuários afetados da Cassandra e envia a carga útil a todos os usuários através do Pusher

Aproveitamos o fato de que o Serviço de Tratamento determina o status de todos os sinalizadores registrando os resultados da avaliação para todos os pares de usuários/dispositivos em um tópico Kafka. Este tópico é ingerido por um trabalho Samza, e os dados são carregados em uma tabela Cassandra para pesquisa de banco de dados. A tabela Cassandra armazena os resultados mais recentes do Serviço de Tratamento para todos os sinalizadores em todas as contas Uber e seu pipeline processa mais de 1.000 eventos por segundo.

Conforme mostrado na Figura 2 abaixo, um processo de envio é desencadeado por engenheiros responsáveis pela mitigação de problemas nos aplicativos:

Ao reverter sinalizadores de indução de interrupção, os usuários da XP da Uber têm a opção de enviar a nova configuração para usuários afetados por meio de um background push silencioso. Isso significa que a nova configuração estará disponível assim que o usuário abrir o aplicativo ao contrário de quando a carga útil é solicitada pelo aplicativo

No background, nossa plataforma de teste A/B, Morpheus, constrói a carga útil que precisa ser enviada aos usuários com base na nova configuração. Esta carga útil é enviada para um serviço interno chamado GroupPusher, juntamente com uma chave que identifica o sinalizador que precisa ser revertido. O GroupPusher é um serviço que requer alguma chave para identificar um conjunto de usuários em Cassandra e uma carga útil e procede para enviar a carga útil a todos os usuários identificados. O GroupPusher, então, puxa a lista de usuários afetados da Cassandra com base nesta chave.

O GroupPusher, em seguida, chama Pusher, um serviço interno que envia a carga útil aos usuários a uma taxa de cerca de 3.000 envios por segundo. O Pusher é responsável por enviar notificações push aos usuários, por exemplo, para que eles saibam que seu motorista está se aproximando do local de embarque: “Seu Uber está chegando agora”. O Pusher, então, envia a carga útil para os clientes móveis via APNs (para iOS) e GCM (para Android).

Esta notificação é silenciosa para o usuário, mas nos bastidores o aplicativo está sendo reconfigurado. Quando a carga útil é recebida, a configuração do sinalizador substitui os estados do sinalizador anteriormente existentes no cache, o que mitiga o erro até que ele possa chamar uma nova carga útil do Serviço de Tratamento com a configuração atualizada.

O push a longo prazo para a XP da Uber

XP Background Push foi desenvolvida como uma ferramenta para atenuar interrupções. Cada um dos aplicativos da Uber contém centenas e, em alguns casos, milhares de sinalizadores responsáveis pela configuração do aplicativo. O OXP Background Push garante que, se surgir um problema, nossa equipe será capaz de abordá-lo, desde que seja determinado por um sinalizador. Por sua vez, essa confiança nos capacita a tornar as experiências móveis mais perfeitas para nossos usuários.

Se você está pronto para o desafio de nos ajudar a expandir a XP da Uber, considere se candidatar para um cargo em nossa equipe!

***

Este artigo é do Uber Engineering. Ele foi escrito por AJ Ribeiro. A tradução foi feita pela Redação iMasters com autorização. Você pode conferir o original em: https://eng.uber.com/xp-background-push/