# app/jobs/disparar_eventos_agendados_job.rb # # Varre os eventos de gatilho `agendado` e dispara os que venceram. Roda de hora # em hora pelo cron do container (config/schedule.rb). # # POR QUE DE HORA EM HORA e não "no horário exato": o evento guarda hora e # frequência escolhidas na tela, e essas podem mudar a qualquer momento — reler # o crontab a cada edição seria acoplar a UI ao cron do sistema. Uma varredura # horária resolve com uma linha fixa no schedule, e `EventoNotificacao#vencido?` # garante que cada evento dispara UMA vez por dia (ele grava ultimo_disparo_em). # # PERÍODO do resumo — recortes FECHADOS, para o número não mudar depois de # enviado: # diária → o dia anterior # semanal → os 7 dias anteriores class DispararEventosAgendadosJob < ApplicationJob queue_as :default def perform(agora = Time.current) EventoNotificacao.ativos.where(gatilho: 'agendado').find_each do |evento| next unless evento.vencido?(agora) inicio, fim = janela(evento, agora) resumo = Analytics::ResumoOperacao.new(inicio: inicio, fim: fim) # Resumo zerado (feriado, fim de semana) só treinaria o leitor a ignorar a # mensagem. Marca como disparado assim mesmo, senão tentaria de hora em # hora até o dia virar. if resumo.vazio? evento.update_columns(ultimo_disparo_em: agora) Rails.logger.info("[Agendados] #{evento.chave}: período sem movimento, nada enviado") next end Notificacao::Gatilhos.resumo_agendado(evento, inicio: inicio, fim: fim) evento.update_columns(ultimo_disparo_em: agora) end rescue StandardError => e Rails.logger.error("[Agendados] #{e.class}: #{e.message}") end private def janela(evento, agora) hoje = agora.to_date evento.frequencia == 'semanal' ? [hoje - 7, hoje - 1] : [hoje - 1, hoje - 1] end end