import os import asyncio import signal import traceback from threading import Event from time import sleep, time from prometheus_client import start_http_server import ingestor.metrics as metrics from ingestor.ingestor import Ingestor exit_signal = Event() POD_ID = os.getenv("HOSTNAME", "localhost") async def main(): start_prometheus_server() ingestor = Ingestor() try: await ingestor.prepare_ingestor() except Exception as e: metrics.APP_ERRORS_TOTAL.labels( pod_id=POD_ID).inc() # Increment errors ingestor.logger.error(f"Failed to prepare ingestor: {e}") exit_signal.set() ingestor.logger.info("Ingestor prepared. Starting main loop.") while not exit_signal.is_set(): start_time = time() # Start loop timer try: await ingestor.loop() metrics.APP_LOOP_COUNT.labels( pod_id=POD_ID).inc() # Increment loop counter # Use asyncio.sleep instead of exit_signal.wait for better async compatibility await asyncio.sleep(ingestor.poll_interval) except KeyboardInterrupt: # Handle Ctrl+C gracefully print("KeyboardInterrupt received. Setting exit_signal flag.") exit_signal.set() except Exception: print("Exception in main loop. Setting exit_signal flag.") traceback.print_exc() metrics.APP_ERRORS_TOTAL.labels( pod_id=POD_ID).inc() # Increment errors exit_signal.set() finally: # Record loop duration duration = time() - start_time metrics.APP_LOOP_DURATION.labels(pod_id=POD_ID).observe(duration) await ingestor.shutdown() metrics.APP_UP.labels(pod_id=POD_ID).set(0) # Mark app as DOWN ingestor.logger.info("Main loop exit_signaled.") # Give Prometheus a chance to scrape one last time before exiting (optional) await asyncio.sleep(5) os._exit(0) def signal_handler(_signum, _frame): print(f"Received signal {_signum}. Setting exit_signal flag.") exit_signal.set() def start_prometheus_server(): try: port = int(os.getenv("HTTP_METRICS_PORT", 9090)) start_http_server(port) print(f"Prometheus server started on port {port}.") metrics.APP_UP.labels(pod_id=POD_ID).set(1) # Mark app as UP except Exception as e: print(f"Failed to start Prometheus server: {e}") os._exit(1) def run_async_main(): """Run the async main function with proper event loop setup""" try: loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) loop.run_until_complete(main()) except KeyboardInterrupt: print("KeyboardInterrupt received in main thread.") exit_signal.set() finally: loop.close() if __name__ == "__main__": signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) signal.signal(signal.SIGHUP, signal_handler) run_async_main()