Refactor Ingestor and OPC Manager for Asynchronous Operations - Updated main function to be asynchronous and integrated asyncio for better concurrency. - Refactored Ingestor methods to support async operations, including prepare_ingestor, loop, and shutdown. - Enhanced IngestorManager and OpcManager with async methods for improved performance and responsiveness. - Replaced blocking calls with await statements to ensure non-blocking behavior during operations. - Added a new run_async_main function to handle the async event loop setup.
99 lines
3.0 KiB
Python
99 lines
3.0 KiB
Python
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()
|