Compartilhar via


Middleware

APLICA-SE A: SDK v4

Middleware é simplesmente uma classe que fica entre o adaptador e sua lógica de bot, adicionada à coleção de middleware do adaptador durante a inicialização. O SDK permite escrever seu próprio middleware ou adicionar o middleware criado por outras pessoas. Toda atividade que entra ou sai do seu bot flui pelo middleware.

O adaptador processa e direciona as atividades de entrada por meio do pipeline de middleware de bot para a lógica do bot e, em seguida, volta para fora novamente. O adaptador processa e direciona atividades de entrada através do pipeline de middleware de bot para a lógica do seu bot e, em seguida, recua novamente.

Antes de entrar no middleware, é importante entender os bots em geral e como eles processam atividades.

Usos para middleware

A pergunta geralmente surge: "Quando devo implementar ações como middleware em vez de usar minha lógica de bot normal?" O Middleware oferece oportunidades extras para interagir com o fluxo de conversa dos usuários antes e depois que cada turno da conversa é processado. O Middleware também permite que você armazene e recupere informações sobre a conversa e chame a lógica de processamento adicional quando necessário. Abaixo estão alguns cenários comuns que mostram onde o middleware pode ser útil.

Olhando ou agindo em todas as atividades

Há muitas situações que exigem que o bot faça algo em cada atividade ou para cada atividade de um determinado tipo. Por exemplo, talvez você queira registrar todas as atividades de mensagens que seu bot recebe ou fornecer uma resposta alternativa se o bot não tiver gerado uma resposta nesta rodada. O Middleware é um ótimo lugar para esses processos, com sua capacidade de agir antes e depois que o restante da lógica do bot for executado.

Modificando ou aprimorando o contexto de turno

Determinadas conversas podem ser muito mais frutíferas se o bot tiver mais informações do que o fornecido na atividade. Nesse caso, o middleware pode examinar o estado da conversa que possui até o momento, consultar uma fonte de dados externa e acrescentar isso ao objeto de contexto de turno antes de passar a execução para a lógica do bot.

O SDK define o middleware de log que pode registrar atividades de entrada e saída, mas você também pode definir seu próprio middleware.

O pipeline de bot middleware

Para cada atividade, o adaptador chama o middleware na ordem em que você o adicionou. O adaptador passa o objeto de contexto para o turno e um delegado próximo, e o middleware chama o delegado para passar o controle para o próximo middleware no pipeline. O middleware também tem a oportunidade de realizar ações após o delegado próximo retornar e antes de concluir o método. Você pode pensar nele como cada objeto middleware tem a primeira e a última chance de agir em relação aos objetos de middleware que o seguem no pipeline.

Por exemplo:

  • O manipulador de turnos do primeiro objeto middleware executa o código antes de chamar em seguida.
    • O manipulador de turnos do segundo objeto middleware executa o código antes de chamar em seguida.
      • O manipulador de turnos do bot é executado e retorna.
    • O manipulador de turnos do segundo objeto middleware executa qualquer código restante antes de retornar.
  • O manipulador de turno do primeiro objeto middleware executa qualquer código restante antes de retornar.

Se o middleware não chamar o próximo delegado, o adaptador não chamará nenhum dos middleware ou manipuladores de turnos do bot subsequentes, e o pipeline será interrompido abruptamente.

Depois que o pipeline de middleware de bot for concluído, o turno terminará e o contexto de turno ficará fora do escopo.

O middleware ou o bot pode gerar respostas e registrar manipuladores de eventos de resposta, mas tenha em mente que as respostas são tratadas em processos separados.

Ordem do middleware

Como a ordem na qual o middleware é adicionado determina a ordem na qual o middleware processa uma atividade, é importante decidir a sequência de que o middleware deve ser adicionado.

Observação

Isso serve para fornecer um padrão comum que funciona para a maioria dos bots, mas considere como cada peça de middleware interagirá com os outros para sua situação.

O middleware que cuida das tarefas de nível mais baixo deve ser adicionado primeiro ao pipeline de middleware de cada bot. Os exemplos incluem registro em log, tratamento de exceções e tradução. Solicite isso dependendo de suas necessidades, como se você deseja que a mensagem de entrada seja traduzida primeiro, antes que as mensagens sejam armazenadas ou se o armazenamento de mensagens deve ocorrer primeiro, o que pode significar que as mensagens armazenadas não seriam traduzidas.

O middleware específico do bot deve ser adicionado ao seu pipeline de middleware por último, sendo aquele que você implementa para fazer algum processamento em cada mensagem enviada ao seu bot. Se o seu middleware usar informações de estado ou outras informações definidas no contexto do bot, adicione-o à fila do pipeline de middleware, posicionando-o após o middleware que modifica o estado ou o contexto.

Curto-circuito

Uma ideia importante em relação ao middleware e ao manuseio de respostas é o curto-circuito. Se a execução for continuar pelas camadas que o seguem, o middleware (ou um manipulador de resposta) é necessário para dar continuidade à execução chamando seu delegado next. Se o próximo delegado não for chamado dentro desse middleware (ou manipulador de resposta), o pipeline associado é interrompido e as camadas subsequentes não serão executadas. Isso significa que toda a lógica do bot e qualquer middleware mais ao longo do pipeline são ignorados. Há uma diferença sutil entre o middleware e o manipulador de resposta, causando um curto-circuito em uma curva.

Quando o middleware interromper um turno, o manipulador de turno do bot não será chamado, mas todo o código de middleware executado antes desse ponto no pipeline ainda será executado até o fim.

Para manipuladores de eventos, não chamar em seguida significa que o evento foi cancelado, o que é muito diferente do middleware ignorando a lógica. Ao não processar o restante do evento, o adaptador nunca o envia.

Dica

Se você interromper abruptamente um evento de resposta, como SendActivities, certifique-se de que é o comportamento que você pretende. Caso contrário, isso pode resultar em dificuldades para corrigir bugs.

Manipuladores de eventos de resposta

Além da lógica do aplicativo e do middleware, os manipuladores de resposta (também conhecidos como manipuladores de eventos ou manipuladores de eventos de atividade) podem ser adicionados ao objeto de contexto. Esses manipuladores são chamados quando a resposta associada ocorre no objeto de contexto atual, antes de executar a resposta real. Esses manipuladores são úteis quando você sabe que deseja fazer algo, seja antes ou depois do evento real, para cada atividade desse tipo durante o restante da atual resposta.

Aviso

Tenha cuidado para não chamar um método de resposta de atividade de dentro de seu respectivo manipulador de eventos de resposta, por exemplo, chamando o método de atividade de envio de dentro de um manipulador de atividade de envio. Isso pode gerar um loop infinito.

Lembre-se de que cada nova atividade obtém um novo thread para executar. Quando o thread para processar a atividade é criado, a lista de manipuladores para essa atividade é copiada para esse novo thread. Nenhum manipulador adicionado após esse ponto será executado para esse evento de atividade específico. Os manipuladores registrados em um objeto de contexto são tratados da mesma forma como o adaptador gerencia o pipeline de middleware. Ou seja, os manipuladores são convocados na ordem em que foram adicionados, e a chamada do próximo delegado passa o controle para o próximo manipulador de eventos registrado. Se um manipulador não chamar o próximo delegado, nenhum dos manipuladores de eventos subsequentes será chamado, o evento é interrompido imediatamente e o adaptador não envia a resposta para o canal.

Manipulando o estado no middleware

Um método comum para salvar o estado é chamar o método salvar alterações no final do manipulador de turnos. Aqui está um diagrama com foco na chamada.

Diagrama de sequência de um turno do bot, com o estado salvo do controlador de turnos do bot.

O problema com essa abordagem é que todas as atualizações de estado feitas de algum middleware personalizado que acontecem depois que o manipulador de turnos do bot tiver retornado não serão salvas no armazenamento durável. A solução é mover a invocação do método para salvar alterações para depois que o middleware personalizado tiver concluído seu processamento, adicionando uma instância do middleware de salvamento automático de alterações ao início da pilha de middleware, ou pelo menos antes de qualquer um dos middlewares que possam atualizar o estado. A execução é mostrada abaixo.

Diagrama de sequência de um turno do bot, com estado salvo pelo middleware.

Adicione os objetos de gerenciamento de estado que precisarão ser atualizados a um objeto conjunto de estado do bot e, em seguida, use isso ao criar o middleware de alterações de salvamento automático.

Recursos adicionais

Você pode dar uma olhada no middleware de registro de transcrição, conforme implementado no SDK do Bot Framework [C# | JS].