# frozen_string_literal: true class ProcessWafEventJob < ApplicationJob queue_as :waf_events def perform(event_data:, headers:) # Handle both single event and events array events_to_process = [] if event_data.key?('events') && event_data['events'].is_a?(Array) # Multiple events in an array events_to_process = event_data['events'] elsif event_data.key?('event_id') # Single event events_to_process = [event_data] else Rails.logger.warn "Invalid event data format: missing event_id or events array" return end events_to_process.each do |single_event_data| begin event_start = Time.current # Generate unique event ID if not provided event_id = single_event_data['event_id'] || SecureRandom.uuid # Create the WAF event record create_start = Time.current event = Event.create_from_waf_payload!(event_id, single_event_data) Rails.logger.debug "Event creation took #{((Time.current - create_start) * 1000).round(2)}ms" # Ensure network range exists for this IP and evaluate policies if needed if event.ip_address.present? begin network_start = Time.current # Single lookup instead of checking has_geo_data? then querying again existing_range = NetworkRange.contains_ip(event.ip_address.to_s).first network_range = existing_range || NetworkRangeGenerator.find_or_create_for_ip(event.ip_address) Rails.logger.debug "Network range lookup/creation took #{((Time.current - network_start) * 1000).round(2)}ms" if network_range Rails.logger.debug "Network range #{network_range.cidr} for event IP #{event.ip_address}" # Queue IPAPI enrichment if we don't have it yet unless network_range.has_network_data_from?(:ipapi) Rails.logger.info "Queueing IPAPI fetch for #{network_range.cidr}" FetchIpapiDataJob.perform_later(network_range_id: network_range.id) end # Evaluate WAF policies inline if needed (lazy evaluation) # Only runs when: network never evaluated OR policies changed since last evaluation if network_range.needs_policy_evaluation? policy_start = Time.current result = WafPolicyMatcher.evaluate_and_mark!(network_range) Rails.logger.debug "Policy evaluation took #{((Time.current - policy_start) * 1000).round(2)}ms" if result[:generated_rules].any? Rails.logger.info "Generated #{result[:generated_rules].length} rules for #{network_range.cidr}" end end end rescue => e Rails.logger.warn "Failed to process network range for event #{event.id}: #{e.message}" end end total_time = ((Time.current - event_start) * 1000).round(2) Rails.logger.info "Processed WAF event #{event_id} in #{total_time}ms" rescue ActiveRecord::RecordInvalid => e Rails.logger.error "Failed to create WAF event: #{e.message}" Rails.logger.error e.record.errors.full_messages.join(", ") rescue => e Rails.logger.error "Error processing WAF event: #{e.message}" Rails.logger.error e.backtrace.join("\n") end end Rails.logger.info "Processed #{events_to_process.count} WAF events" end end