Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

248
Visualizações
Hangfire en una sola aplicación en múltiples servidores físicos

Estoy ejecutando hangfire en una sola aplicación web, mi aplicación se ejecuta en 2 servidores físicos pero hangfire está en 1 base de datos.

Por el momento, estoy generando un servidor para cada cola, porque cada cola necesito ejecutar 1 trabajador a la vez y deben estar en orden. los configuro asi

 // core services.AddHangfire(options => { options.SetDataCompatibilityLevel(CompatibilityLevel.Version_170); options.UseSimpleAssemblyNameTypeSerializer(); options.UseRecommendedSerializerSettings(); options.UseSqlServerStorage(appSettings.Data.DefaultConnection.ConnectionString, storageOptions); }); // add multiple servers, this way we get to control how many workers are in each queue services.AddHangfireServer(options => { options.ServerName = "workflow-queue"; options.WorkerCount = 1; options.Queues = new string[] { "workflow-queue" }; options.SchedulePollingInterval = TimeSpan.FromSeconds(10); }); services.AddHangfireServer(options => { options.ServerName = "alert-schedule"; options.WorkerCount = 1; options.Queues = new string[] { "alert-schedule" }; options.SchedulePollingInterval = TimeSpan.FromMinutes(1); }); services.AddHangfireServer(options => { options.ServerName = string.Format("trigger-schedule"); options.WorkerCount = 1; options.Queues = new string[] { "trigger-schedule" }; options.SchedulePollingInterval = TimeSpan.FromMinutes(1); }); services.AddHangfireServer(options => { options.ServerName = "report-schedule"; options.WorkerCount = 1; options.Queues = new string[] { "report-schedule" }; options.SchedulePollingInterval = TimeSpan.FromMinutes(1); }); services.AddHangfireServer(options => { options.ServerName = "maintenance"; options.WorkerCount = 5; options.Queues = new string[] { "maintenance" }; options.SchedulePollingInterval = TimeSpan.FromMinutes(10); });

Mi problema es que está generando múltiples colas en los servidores, con diferentes puertos. ingrese la descripción de la imagen aquí

En mi código, estoy tratando de detener la ejecución de trabajos si están en cola/reintentando, pero si el trabajo se está ejecutando en un servidor físico diferente, no se encuentra y se vuelve a poner en cola.

Aquí está el código para verificar si ya se está ejecutando

 public async Task<bool> IsAlreadyQueuedAsync(PerformContext context) { var disableJob = false; var monitoringApi = JobStorage.Current.GetMonitoringApi(); // get the jobId, method and queue using performContext var jobId = context.BackgroundJob.Id; var methodInfo = context.BackgroundJob.Job.Method; var queueAttribute = (QueueAttribute)Attribute.GetCustomAttribute(context.BackgroundJob.Job.Method, typeof(QueueAttribute)); // enqueuedJobs var enqueuedjobStatesToCheck = new[] { "Processing" }; var enqueuedJobs = monitoringApi.EnqueuedJobs(queueAttribute.Queue, 0, 1000); var enqueuedJobsAlready = enqueuedJobs.Count(e => e.Key != jobId && e.Value != null && e.Value.Job != null && e.Value.Job.Method.Equals(methodInfo) && enqueuedjobStatesToCheck.Contains(e.Value.State)); if (enqueuedJobsAlready > 0) disableJob = true; // scheduledJobs if (!disableJob) { // check if there are any scheduledJobs that are processing var scheduledJobs = monitoringApi.ScheduledJobs(0, 1000); var scheduledJobsAlready = scheduledJobs.Count(e => e.Key != jobId && e.Value != null && e.Value.Job != null && e.Value.Job.Method.Equals(methodInfo)); if (scheduledJobsAlready > 0) disableJob = true; } // failedJobs if (!disableJob) { var failedJobs = monitoringApi.FailedJobs(0, 1000); var failedJobsAlready = failedJobs.Count(e => e.Key != jobId && e.Value != null && e.Value.Job != null && e.Value.Job.Method.Equals(methodInfo)); if (failedJobsAlready > 0) disableJob = true; } // if runBefore is true, then lets remove the current job running, else it will write a "successful" message in the logs if (disableJob) { // use hangfire delete, for cleanup BackgroundJob.Delete(jobId); // create our sqlBuilder to remove the entries altogether including the count var sqlBuilder = new SqlBuilder() .DELETE_FROM("Hangfire.[Job]") .WHERE("[Id] = {0};", jobId); sqlBuilder.Append("DELETE TOP(1) FROM Hangfire.[Counter] WHERE [Key] = 'stats:deleted' AND [Value] = 1;"); using (var cmd = _context.CreateCommand(sqlBuilder)) await cmd.ExecuteNonQueryAsync(); return true; } return false; }

Cada método tiene algo así como los siguientes atributos también

 public interface IAlertScheduleService { [Hangfire.Queue("alert-schedule")] [Hangfire.DisableConcurrentExecution(60 * 60 * 5)] Task RunAllAsync(PerformContext context); }

Implementación simple de la interfaz.

 public class AlertScheduleService : IAlertScheduleService { public Task RunAllAsync(PerformContext context) { if (IsAlreadyQueuedAsync(context)) return; // guess it isnt queued, so run it here.... } }

Así es como agrego mis trabajos programados

 //// our recurring jobs //// set these to run hourly, so they can play "catch-up" if needed RecurringJob.AddOrUpdate<IAlertScheduleService>(e => e.RunAllAsync(null), Cron.Hourly(0), queue: "alert-schedule");

¿Por qué pasó esto? ¿Cómo puedo evitar que suceda?

over 4 years ago · Santiago Trujillo
1 Respostas
Responde à pergunta

0

Algo así como un tiro ciego, que evita que un trabajo se ponga en cola si un trabajo ya está en cola en la misma cola. La lógica de intento y captura es bastante fea, pero no tengo una mejor idea en este momento... Además, no estoy seguro de que la lógica de bloqueo siempre impida tener dos trabajos en EnqueudState, pero debería ayudar de todos modos. Tal vez mezclar con un IApplyStateFilter.

 public class DoNotQueueIfAlreadyQueued : IElectStateFilter { public void OnStateElection(ElectStateContext context) { if (context.CandidateState is EnqueuedState) { EnqueuedState es = context.CandidateState as EnqueuedState; IDisposable distributedLock = null; try { while (distributedLock == null) { try { distributedLock = context.Connection.AcquireDistributedLock($"{nameof(DoNotQueueIfAlreadyQueued)}-{es.Queue}", TimeSpan.FromSeconds(1)); } catch { } } var m = context.Storage.GetMonitoringApi(); if (m.EnqueuedCount(es.Queue) > 0) { context.CandidateState = new DeletedState(); } } finally { distributedLock.Dispose(); } } } }

El filtro se puede declarar como en esta respuesta.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda