public TareaProgramada UpdateIsActive(TareaProgramada entity, bool?isActive) { Check.NotNull(entity, nameof(entity)); return(isActive.HasValue && isActive.Value ? entity.Activar() : entity.Desactivar()); }
/// <summary> /// Programa finalizado /// </summary> /// <param name="prg"></param> void FinServicio(TareaProgramada prg, Exception ex) { lock (bloqueo) { log.Info($"Finalizando tarea {prg.ID}"); // Avisamos que ha terminado OnFinTarea(prg.ID, prg.Tarea, ex); // Si es Auto borramos la tarea en si. No importa hacer dispose porque las tareas se registras como scoped if (prg.AutoCrear) { prg.Tarea = null; } prg.Task = null; prg.SiguienteInicio = prg.Programacion.SiguienteEjecucion(DateTime.Now); if (prg.SiguienteInicio == DateTime.MinValue) // Si no es periodico, lo borramos { log.Info($"Tarea {prg.ID} eliminada"); DesprogramaTarea(prg); } else { log.Info($"Tarea {prg.ID} reprogramado para {prg.SiguienteInicio.FechaServidorFechaUsuario()}"); } // Liberamos, la proxima llamada creara otro prg.CancellationTokenSource = null; } EscaneaTareas(); }
/// <summary> /// Programa una tarea /// </summary> /// <param name="id"></param> /// <param name="tarea"></param> /// <param name="tarea"></param> /// <param name="tipoTarea"></param> /// <param name="procesosIncompatibles">Coleccion de IDs de tareas incompatibles</param> void ProgramaTarea(string id, ITarea tarea, Type tipoTarea, IProgramador programacion, IEnumerable <string> procesosIncompatibles = null) { if ((tarea == null && tipoTarea == null) || programacion == null) { throw new ArgumentException("La tarea y la programación deben especificarse"); } if (tarea != null && tipoTarea != null) { throw new ArgumentException("Solo se puede especificar la tarea o su tipo"); } if (tipoTarea != null && container == null) { throw new ArgumentException($"El contenedor es nulo y la tarea tipo {tipoTarea.Name} lo necesita"); } if (tipoTarea != null && container.GetRegistration(tipoTarea) == null) { throw new ArgumentException($"El contenedor no conoce a {tipoTarea.Name}"); } if (string.IsNullOrWhiteSpace(id)) { throw new ArgumentException($"La tarea debe tener un Id unico"); } log.Info($"Programando tarea {id} con el programador {programacion.GetType()}"); DateTime primeraEjecucion = programacion.PrimeraEjecucion(DateTime.Now); if (primeraEjecucion < DateTime.Now.AddSeconds(-5)) { log.Warn($"La tarea {id} ha caducado antes de iniciarse"); return; } log.Info($"Servicio periodico registrado {id} en fecha {primeraEjecucion:g}"); TareaProgramada prog = new TareaProgramada(); prog.ID = id; prog.Programacion = programacion; prog.Tarea = tarea; prog.TipoTarea = tipoTarea; prog.SiguienteInicio = primeraEjecucion; if (procesosIncompatibles != null) { prog.ProcesosIncompatibles.AddRange(procesosIncompatibles); } lock (bloqueo) { if (tareasProgramadas.Where(x => x.ID == id).FirstOrDefault() != null) { log.Warn($"La tarea {id} está duplicada"); return; } tareasProgramadas.Add(prog); } EscaneaTareas(); }
public async Task <IScheduledTask> Create(ScheduledTaskDto dto) { TareaProgramada tarea = TareasProgramadaFactory.CrearTareaProgramada(dto.Name, dto.Identifier, dto.Cron).WithTimeout(dto.Timeout); UpdateIsActive(tarea, dto.IsActive); return(await this.Repository.InsertAsync(tarea)); }
/// <summary> /// Elimina una tarea de la lista y si implementa IDisposable lo ejecuta sobre la tarea /// </summary> /// <param name="prg"></param> private void DesprogramaTarea(TareaProgramada prg) { IDisposable dsp = prg.Tarea as IDisposable; if (dsp != null) { dsp.Dispose(); } tareasProgramadas.Remove(prg); }
/// <summary> /// Escanea las tareas y si hay programa el timer para la proxima en el tiempo /// </summary> private void EscaneaTareas() { // ¿Esta parado el servicio? if (!funcionando) { return; } log.Debug("Escaneando tareas en el programador"); lock (bloqueo) { if (timer != null) { timer.Dispose(); timer = null; } DateTime actuales = DateTime.Now; var siguiente = new TareaProgramada(); // Para simplificar la busqueda siguiente.SiguienteInicio = DateTime.MaxValue; foreach (TareaProgramada cls in tareasProgramadas) { if (cls.SiguienteInicio <= actuales && !cls.Funcionando) { log.Warn($"Llegamos tarde a la tarea {cls.ID} y la lanzamos ahora"); Task.Run(() => EjecutaPrograma(cls)); // ¿Llegamos tarde? arrancamos ahora } else { if (cls.SiguienteInicio < siguiente.SiguienteInicio && !cls.Funcionando) { siguiente = cls; } } } if (siguiente.SiguienteInicio < DateTime.MaxValue) // Si hemos encontrado algo, programamos el timer { TimeSpan arranque = siguiente.SiguienteInicio - DateTime.Now; if (arranque < TimeSpan.Zero) { arranque = TimeSpan.FromMilliseconds(50); // Se ejecuta dentro de 50 ms } timer = new Timer(new TimerCallback(LanzadoTimer), siguiente, arranque, new TimeSpan(-1)); } if (timer == null) { log.Info("No hay mas servicios a programar"); } else { log.Info($"Proximo servicio nombre {siguiente.ID} programado para {siguiente.SiguienteInicio}"); } } }
public async Task Delete(int id) { TareaProgramada tarea = await this.Repository.GetAsync(id); if (tarea == null) { throw new DataException("No existe la tarea programada con id: " + id); } await this.Repository.DeleteAsync(tarea); }
/// <summary> /// Hace la ejecucion de la tarea /// </summary> /// <param name="cls"></param> /// <param name="bloqueado"></param> /// <returns></returns> private async Task HazEjecutaTarea(TareaProgramada cls, bool bloqueado) { if (!bloqueado) { log.Info("La tarea no se ha podido bloquear, simulamos su ejecución por coherencia"); } var scope = AseguraTarea(cls); try { OnInicioTarea(cls.ID, cls.Tarea); try { log.Info($"Ejecutando {cls.ID}. Tarea bloqueada: {bloqueado}"); if (cls.Tarea != null) { if (bloqueado) { await cls.Tarea.Ejecutar(cls.CancellationTokenSource.Token).ConfigureAwait(false); } } else { log.Error($"La tarea con ID {cls.ID} no se ha creado correctamente"); } log.Info($"Fin de ejecucion {cls.ID}"); // Avisamos del fin de la tarea FinServicio(cls, null); } catch (Exception ex) { log.Error(ex, $"Error al ejecutar la tarea {cls.ID}"); FinServicio(cls, ex); } } finally { if (scope != null) { scope.Dispose(); } } }
Scope AseguraTarea(TareaProgramada cls) { if (cls.AutoCrear) { try { var scope = AsyncScopedLifestyle.BeginScope(container); cls.Tarea = container.GetInstance(cls.TipoTarea) as ITarea; return(scope); } catch (Exception ex) { log.Error(ex, $"Error creando la tarea con ID {cls.ID}"); } } return(null); }
private void EjecutaPrograma(TareaProgramada cls) { lock (bloqueo) { log.Info($"Lanzando programa {cls.ID}"); log.Debug("Comprobando si es incompatible con otra tarea en funcionamiento"); if (cls.ProcesosIncompatibles.Count > 0) { bool incompatibles = tareasProgramadas.Any(q => q.Funcionando && cls.ProcesosIncompatibles.Contains(q.ID)); if (incompatibles) { log.Warn($"Tarea {cls.ID} ha sido pospuesta"); cls.SiguienteInicio = DateTime.Now.AddMinutes(1); // Posponemos un minuto Task.Run(() => EscaneaTareas()); // Buscamos otras posibles tareas a lanzar o simplemente reprogramamos return; } } var cs = cls.CancellationTokenSource; var tareaActual = cls.Task = Task.Run(async() => { var bloqueado = await BlindaAsync(() => bloqueoTarea.BloqueaTareaAsync(cls.ID)).ConfigureAwait(false); try { await HazEjecutaTarea(cls, bloqueado).ConfigureAwait(false); } finally { if (bloqueado) { await BlindaAsync(() => bloqueoTarea.DesBloqueaTareaAsync(cls.ID)).ConfigureAwait(false); } } }, cls.CancellationTokenSource.Token); // Cuando acabe, liberamos memoria cls.Task.ContinueWith((t) => { // Liberamos el cancellation token cs.Dispose(); // Liberamos recursos tareaActual.Dispose(); }); } }
public async Task <IScheduledTask> Update(ScheduledTaskDto dto) { TareaProgramada entity = await this.Repository.GetAsync(dto.Id); if (entity == null) { throw new DataException("No existe la tarea programada con id : " + dto.Id); } entity.ConCron(dto.Cron); entity.ConIdentificador(dto.Identifier); entity.ConNombre(dto.Name); entity.WithTimeout(dto.Timeout); UpdateIsActive(entity, dto.IsActive); return(await this.Repository.UpdateAsync(entity)); }