MVFC.LongPolling
1.0.4
dotnet add package MVFC.LongPolling --version 1.0.4
NuGet\Install-Package MVFC.LongPolling -Version 1.0.4
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="MVFC.LongPolling" Version="1.0.4" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="MVFC.LongPolling" Version="1.0.4" />
<PackageReference Include="MVFC.LongPolling" />
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add MVFC.LongPolling --version 1.0.4
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: MVFC.LongPolling, 1.0.4"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package MVFC.LongPolling@1.0.4
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=MVFC.LongPolling&version=1.0.4
#tool nuget:?package=MVFC.LongPolling&version=1.0.4
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
MVFC.LongPolling
Uma biblioteca leve e eficiente de long polling via Redis Pub/Sub para .NET,
com suporte a CancellationToken configurável e payload tipado.
Objetivo
Permitir que clientes HTTP aguardem resultados assíncronos (jobs, webhooks, processamentos) de forma simples, sem polling cego ou WebSockets, usando o canal Pub/Sub do Redis como mecanismo de notificação.
Funcionalidades
- Redis Pub/Sub: Subscription real por canal, sem polling de chave.
- Timeout configurável: Tempo máximo de espera global ou por chamada via
LongPollingOptions. - CancellationToken: Respeita desconexão do cliente HTTP automaticamente.
- Payload tipado:
WaitAsync<T>desserializa o resultado diretamente viaSystem.Text.Json. - Entrega confirmada:
PublishAsyncretornafalsese nenhum subscriber estava ativo. - Sincronização determinística:
WaitUntilReadyAsyncgarante que a subscription está ativa antes de publicar. - Configuração Fluente: Setup simples no
Program.cs. - Prefixo de canal: Isolamento de ambientes via
KeyPrefix.
Instalação
dotnet add package MVFC.LongPolling
Configuração
Básica
builder.Services.AddLongPolling("localhost:6379", cfg =>
{
cfg.DefaultTimeout = TimeSpan.FromSeconds(30);
cfg.KeyPrefix = "poll";
});
Com IConnectionMultiplexer existente
builder.Services.AddLongPolling(existingMultiplexer, cfg =>
{
cfg.DefaultTimeout = TimeSpan.FromSeconds(20);
});
Uso
Aguardar resultado (string)
app.MapGet("/poll/{jobId}", async (
string jobId,
ILongPollingService polling,
CancellationToken ct) =>
{
var result = await polling.WaitAsync(jobId, cancellationToken: ct);
return result is null
? Results.NoContent() // timeout
: Results.Ok(result);
});
Aguardar resultado tipado
app.MapGet("/poll/{jobId}/typed", async (
string jobId,
ILongPollingService polling,
CancellationToken ct) =>
{
var result = await polling.WaitAsync<OrderCompletedEvent>(jobId, cancellationToken: ct);
return result is null
? Results.NoContent()
: Results.Ok(result);
});
Notificar conclusão de job
app.MapPost("/notify/{jobId}", async (
string jobId,
NotifyRequest req,
ILongPollingService polling) =>
{
var delivered = await polling.PublishAsync(jobId, req.Payload);
return delivered
? Results.Accepted()
: Results.NotFound($"Nenhum subscriber ativo para o canal '{jobId}'.");
});
Opções por chamada
var options = new LongPollingOptions(
Timeout: TimeSpan.FromSeconds(10),
KeyPrefix: "custom");
var result = await polling.WaitAsync(jobId, options, cancellationToken: ct);
Parâmetros de Configuração
| Parâmetro | Tipo | Padrão | Descrição |
|---|---|---|---|
DefaultTimeout |
TimeSpan |
30 segundos |
Tempo máximo de espera por mensagem |
KeyPrefix |
string |
longpolling |
Prefixo do canal Redis |
Fluxo de funcionamento
Cliente HTTP Servidor Redis
──────────── ──────── ─────
GET /poll/{id} ──► WaitAsync()
SubscribeAsync(canal) ──► SUBSCRIBE poll:id
WaitUntilReadyAsync() ◄── (confirmado)
◄── Worker: PublishAsync()
mensagem recebida ◄── PUBLISH poll:id payload
GET retorna ◄── Results.Ok(payload)
Exemplo de Fluxo de funcionamento de cenário em produção para pagamento
Fluxo padrão — mensagem recebida
Cliente HTTP API Pedidos API Pagamentos
──────────── ─────────── ──────────────
POST /orders ──► Cria pedido
WaitAsync(orderId) ──► Processa pagamento
PublishAsync(orderId, "approved")
◄── "approved"
200 OK ◄── Results.Ok(status)
Timeout — sem resposta do pagamento
Cliente HTTP API Pedidos API Pagamentos
──────────── ─────────── ──────────────
POST /orders ──► Cria pedido
WaitAsync(orderId) ──► Processa pagamento
(aguarda...) (sem PublishAsync)
timeout atingido
504 GW Timeout ◄── Results.StatusCode(504)
Pagamento recusado
Cliente HTTP API Pedidos API Pagamentos
──────────── ─────────── ──────────────
POST /orders ──► Cria pedido
WaitAsync(orderId) ──► Processa pagamento
PublishAsync(orderId, "rejected")
◄── "rejected"
422 Unprocessable ◄── Results.UnprocessableEntity(status)
Cliente desconecta antes da resposta
Cliente HTTP API Pedidos API Pagamentos
──────────── ─────────── ──────────────
POST /orders ──► Cria pedido
WaitAsync(orderId) ──► Processa pagamento
✗ desconecta
CancellationToken cancelado
WaitAsync lança OperationCanceledException
(resposta descartada)
Publish sem subscriber ativo
Cliente HTTP API Pedidos API Pagamentos
──────────── ─────────── ──────────────
PublishAsync(orderId, "approved")
delivered = false
(nenhum WaitAsync ativo para orderId)
404 Not Found ◄── Results.NotFound(...)
Estrutura do Projeto
- src: Código-fonte da biblioteca
MVFC.LongPolling. - playground: API de exemplo para validar o comportamento com Aspire.
- tests: Testes de integração com Aspire + Redis.
Licença
Apache License 2.0. Consulte o arquivo LICENSE.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
net10.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.3)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.3)
- Microsoft.Extensions.Options (>= 10.0.3)
- SonarAnalyzer.CSharp (>= 10.19.0.132793)
- StackExchange.Redis (>= 2.11.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.