Estou reescrevendo um aplicativo Windows Forms que precisa fazer uma chamada para um servidor de banco de dados. A chamada pode levar até 30 segundos, então quero armazenar o resultado em cache (ele não muda).
Como vários eventos podem desencadear a necessidade dessas informações, dependendo de quais outras informações são inseridas ou escolhidas na IU. Os diferentes componentes da UI que podem precisar dessas informações não estão cientes uns dos outros.
Eu só quero fazer essa chamada de banco de dados uma vez. Portanto, se você, o usuário, acionar aquela chamada de banco de dados de 30 segundos (que é feita de forma assíncrona) e, 5 segundos depois, outra parte do aplicativo descobrir a necessidade dessas informações, não quero que o aplicativo dispare outro banco de dados solicitação, só porque o cache ainda está vazio. Quero esperar os 25 segundos restantes até que as informações estejam disponíveis, pegar o valor armazenado em cache e retornar.
Mas não consigo entender como estruturar isso, tanto em termos de dados quanto de código.
Vejo esse cenário como duas (ou mais) solicitações, que estão na fila de alguma forma, e uma vez que a primeira é atendida pela chamada do banco de dados, a segunda pega o valor do resultado agora armazenado em cache e retorna. Se, mais tarde, alguma outra coisa – uma terceira coisa – precisar desta informação, a solicitação pegará o valor armazenado em cache e retornará imediatamente.
Estou me perguntando se existe um padrão interno ou conjunto de estruturas de dados para fazer isso no .NET. Sinto como se isso fosse quase - mas não exatamente - um async/await
padrão básico, exceto que várias coisas aguardam o mesmo resultado.
O que é esse padrão/arquitetura em que estou pensando, mas não consigo visualizar?
O padrão onde múltiplas coisas aguardam o mesmo resultado é apenas... múltiplas coisas aguardando a mesma tarefa. É isso. Não há mágica.
O .NET
Task
pode ser aguardado várias vezes sem problemas e armazenar seu resultado indefinidamente (isso é diferente doValueTask
, que só pode ser aguardado uma vez). Se você aguardar uma tarefa já concluída, ela retornará o resultado imediatamente. Portanto, em vez de armazenar em cache o resultado, você pode simplesmente armazenar em cache a tarefa.Com isso em mente, basta manter uma referência à tarefa em si.
Na primeira vez que você chama o método, a consulta é disparada e a tarefa é armazenada. As chamadas subsequentes apenas retornam a mesma tarefa, então todos aguardarão por ela, e a consulta efetivamente só será executada uma vez.
Agora, isso é um pouco ingênuo, porque não trata nenhum erro. Mas deve ser o suficiente para você começar.