Hangfire en ASP.NET Core: trabajos en segundo plano
Este artículo forma parte del pilar .NET y arquitectura.
Hangfire resuelve un problema concreto en ASP.NET Core: sacar de una petición HTTP el trabajo que no necesita terminar antes de responder. Enviar un correo, procesar un archivo o reintentar una integración son buenos ejemplos.
A diferencia de lanzar un Task.Run, Hangfire serializa el trabajo y lo guarda para que pueda sobrevivir a reinicios, registrar su estado y reintentarse. Esa persistencia es útil, pero no elimina las decisiones de operación: un trabajo puede ejecutarse más de una vez, fallar a mitad o quedarse esperando un recurso externo.
Qué es Hangfire y cómo funciona
Hangfire administra trabajos en segundo plano desde que se crean hasta que se ejecutan. Incluye persistencia, estados, reintentos y un Dashboard operativo. No sustituye una arquitectura de mensajería distribuida en todos los escenarios, pero resulta práctico cuando el trabajo pertenece a la misma aplicación .NET.
Su arquitectura tiene tres piezas:
- Cliente: crea el trabajo y lo envía al almacenamiento.
- Almacenamiento: conserva la definición, el estado y la información necesaria para procesarlo.
- Servidor: obtiene trabajos del almacenamiento y los ejecuta. En una aplicación pequeña, el mismo proceso puede actuar como cliente y servidor.

Arquitectura básica de Hangfire
En el texto uso “trabajo”, que corresponde al término job de Hangfire. En artículos antiguos también lo llamaba “tarea”; aquí se refieren al mismo proceso en segundo plano.
Configurar Hangfire en ASP.NET Core
Para reproducir el ejemplo instala Hangfire.AspNetCore y Hangfire.MemoryStorage. En producción instala el proveedor correspondiente al almacenamiento elegido, como SQL Server o Redis.
En Program.cs, registra Hangfire y levanta un servidor:
builder.Services.AddHangfire(configuration => configuration.UseMemoryStorage());builder.Services.AddHangfireServer();El almacenamiento en memoria reduce el ruido del ejemplo, pero no es una opción de producción: al reiniciar la aplicación se pierde su estado. Para una aplicación real, usa almacenamiento persistente, mueve el trabajo a una clase inyectable y no serialices secretos ni información sensible en sus argumentos.
Tipos de trabajos en Hangfire
Trabajo inmediato o fire-and-forget
Un trabajo inmediato se crea sin esperar su resultado. Hangfire lo almacena y devuelve un identificador que permite seguir su estado.
app.MapPost("/notificacion", () =>{ var jobId = BackgroundJob.Enqueue(() => SendEmail()); return Results.Accepted(value: new { jobId });});Enqueue no espera a que SendEmail termine. La API puede responder mientras un servidor de Hangfire procesa el trabajo.
Trabajos retrasados
Un trabajo retrasado establece un tiempo mínimo antes de que pueda comenzar:
app.MapPost("/espera", () =>{ var jobId = BackgroundJob.Schedule( () => SendEmail(), TimeSpan.FromSeconds(10)); return Results.Accepted(value: new { jobId });});El término mínimo importa: la ejecución depende del sondeo, la disponibilidad del servidor y la carga. No uses un trabajo retrasado como si fuera un temporizador de tiempo real.
Trabajos recurrentes
RecurringJob.AddOrUpdate registra un trabajo con una frecuencia equivalente a cron:
app.MapPost("/recurrente", () =>{ RecurringJob.AddOrUpdate( "send-email", () => SendEmail(), Cron.Minutely); return Results.NoContent();});El identificador send-email debe ser estable y único. Volver a llamar AddOrUpdate con ese identificador actualiza la definición existente en vez de crear otra.
Continuaciones
Una continuación crea un trabajo que depende de otro:
app.MapPost("/continuation", () =>{ var jobId = BackgroundJob.Enqueue(() => SendEmail()); BackgroundJob.ContinueJobWith(jobId, () => CrearLog()); return Results.Accepted(value: new { jobId });});En un flujo real también debes decidir qué debe pasar con la continuación si el primer trabajo falla.
Proteger el Dashboard de Hangfire
En desarrollo puedes activar el Dashboard desde Program.cs:
app.UseHangfireDashboard();La interfaz permite inspeccionar argumentos, reintentar, eliminar y disparar trabajos. No debe quedar expuesta públicamente. En ASP.NET Core, configura autenticación antes del Dashboard y exige una política:
app.UseAuthentication();app.UseAuthorization();
app.MapHangfireDashboard("/hangfire") .RequireAuthorization("HangfireDashboard");La política debe limitar el acceso a operadores autorizados. Permitir a cualquier usuario autenticado sigue siendo demasiado amplio para muchas aplicaciones.

Dashboard de Hangfire
Llevar Hangfire a producción
Antes de desplegar revisaría, como mínimo:
- almacenamiento persistente y copias de seguridad
- idempotencia ante reintentos o ejecuciones duplicadas
- timeouts, cancelación y política de reintentos
- colas y cantidad de workers según el tipo de carga
- autorización del Dashboard y ausencia de secretos en argumentos
- logs, métricas, alertas y correlación con la petición original
Usaría Hangfire cuando una aplicación .NET necesita trabajos persistentes, reintentos y operación visible sin introducir todavía una plataforma de mensajería completa. No lo elegiría por defecto para integrar muchos servicios independientes, mover grandes volúmenes de eventos o resolver flujos que requieren garantías distribuidas más estrictas.
La decisión clave no es solo “ejecutar después”, sino definir qué ocurre cuando el trabajo falla o se repite. Hangfire aporta la infraestructura; esas decisiones siguen siendo responsabilidad del equipo.
Si quieres seguir aprendiendo sobre estos temas, te invito a ver mis otras publicaciones.
