defmodule DaProductApp.TerminalManagement.RuleValidationWorker do @moduledoc """ Periodic worker that validates rule consistency and fixes any discrepancies. Runs every hour to ensure the system remains consistent. """ use GenServer require Logger alias DaProductApp.TerminalManagement.TerminalGroupService @validation_interval 60 * 60 * 1000 # 1 hour in milliseconds # ============================================================================ # Client API # ============================================================================ def start_link(opts) do GenServer.start_link(__MODULE__, opts, name: __MODULE__) end def run_validation_now do GenServer.cast(__MODULE__, :validate_now) end def get_last_validation do GenServer.call(__MODULE__, :get_last_validation) end # ============================================================================ # Server Callbacks # ============================================================================ @impl true def init(_opts) do # Schedule first validation in 5 minutes after startup Process.send_after(self(), :validate, 5 * 60 * 1000) Logger.info("Rule Validation Worker started - will run every hour") {:ok, %{ last_validation: nil, validation_count: 0, fixes_applied: 0 }} end @impl true def handle_info(:validate, state) do Logger.info("Starting scheduled rule validation") fixes = perform_validation() # Schedule next validation Process.send_after(self(), :validate, @validation_interval) new_state = %{state | last_validation: DateTime.utc_now(), validation_count: state.validation_count + 1, fixes_applied: state.fixes_applied + fixes } Logger.info("Rule validation completed - applied #{fixes} fixes") {:noreply, new_state} end @impl true def handle_cast(:validate_now, state) do Logger.info("Starting manual rule validation") fixes = perform_validation() new_state = %{state | last_validation: DateTime.utc_now(), validation_count: state.validation_count + 1, fixes_applied: state.fixes_applied + fixes } Logger.info("Manual rule validation completed - applied #{fixes} fixes") {:noreply, new_state} end @impl true def handle_call(:get_last_validation, _from, state) do {:reply, state, state} end # ============================================================================ # Validation Logic # ============================================================================ defp perform_validation do fixes = 0 # 1. Check for terminals that should be in groups but aren't fixes = fixes + validate_missing_assignments() # 2. Check for terminals that shouldn't be in groups but are fixes = fixes + validate_invalid_assignments() # 3. Check for inactive rules with active assignments fixes = fixes + validate_rule_consistency() # 4. Update terminal counts for all groups update_group_counts() fixes end defp validate_missing_assignments do Logger.debug("Validating missing assignments") # This would re-apply all rules to catch any missed terminals case TerminalGroupService.apply_all_rules() do {:ok, count} -> Logger.debug("Re-applied #{count} rules during validation") 0 # Assuming this just ensures consistency rather than fixes {:error, reason} -> Logger.error("Failed to re-apply rules during validation: #{inspect(reason)}") 0 end end defp validate_invalid_assignments do Logger.debug("Validating invalid assignments") # This could check for assignments that no longer match their rules # For now, we trust the event-driven system 0 end defp validate_rule_consistency do Logger.debug("Validating rule consistency") # Check for assignments linked to inactive rules # Clean them up if found 0 end defp update_group_counts do Logger.debug("Updating group terminal counts") # The counts are calculated dynamically, so this is mainly for logging stats = TerminalGroupService.get_group_statistics() Logger.debug("Current group statistics: #{inspect(stats)}") end end