Files
upi_inward_file_based/scheduler.py
T
2026-06-16 15:37:55 +05:30

156 lines
5.1 KiB
Python

#!/usr/bin/env python3
"""
/UPI file processing scheduler.
Runs polling loop every 30 minutes to process new files.
"""
import signal
import time
import sys
from datetime import datetime
from logging_config import get_logger, setup_logging
from config import get_config
from db import OracleConnector, Repository
from sftp import SFTPClient, FileMonitor
from processors import FileProcessor
logger = get_logger(__name__)
class Scheduler:
"""Main scheduler for UPI file processing."""
def __init__(self):
self.config = get_config()
self.config.validate()
self.running = True
self.cycle_count = 0
signal.signal(signal.SIGTERM, self._signal_handler)
signal.signal(signal.SIGINT, self._signal_handler)
def _signal_handler(self, signum, frame):
logger.info(f"Received signal {signum}, shutting down gracefully...")
self.running = False
def initialize_database(self):
try:
connector = OracleConnector()
if connector.test_connection():
logger.info("Database connection test passed")
repository = Repository()
return True
else:
logger.error("Database connection test failed")
return False
except SystemExit as e:
logger.error(f"Database initialization failed: {e}")
raise
except Exception as e:
logger.error(f"Error initializing database: {e}", exc_info=True)
return False
def run_processing_cycle(self):
self.cycle_count += 1
logger.info(f"=== Starting processing cycle {self.cycle_count} ===")
sftp_client = SFTPClient()
repository = Repository()
try:
if not sftp_client.connect():
logger.error("Failed to connect to SFTP server")
return
monitor = FileMonitor(sftp_client)
new_files = []
today_str = datetime.now().strftime("%d%m%Y")
logger.info(f"listing file for {today_str}")
for bank_code in self.config.bank_codes:
bank_processed = repository.get_processed_files(bank_code)
remote_path = f"{self.config.sftp_base_path}/{bank_code}/UPI"
pattern = f"*_{today_str}_*_UPI.txt.gz"
files = sftp_client.list_files(remote_path, pattern=pattern)
for filename in files:
if filename not in bank_processed:
full_path = f"{remote_path}/{filename}"
new_files.append((filename, bank_code, full_path))
logger.info(f"Found new file: {filename} (bank: {bank_code})")
else:
logger.debug(f"Skipping already processed file for {bank_code}: {filename}")
if not new_files:
logger.info("No new files to process")
return
logger.info(f"Found {len(new_files)} new files to process")
processor = FileProcessor(repository, sftp_client)
stats = processor.process_files(new_files)
logger.info(f"Cycle {self.cycle_count} complete:")
logger.info(f" Total files: {stats['total']}")
logger.info(f" Successful: {stats['successful']}")
logger.info(f" Failed: {stats['failed']}")
# FIXED INDENTATION BLOCK
if stats['successful'] > 0:
logger.info("Calling upi_api_txn_post procedure for all inserted transactions...")
if repository.call_upi_api_txn_post():
logger.info("Transaction post-processing completed successfully")
else:
logger.error("Transaction post-processing failed")
except Exception as e:
logger.error(f"Error in processing cycle: {e}", exc_info=True)
finally:
sftp_client.disconnect()
def run(self):
logger.info("=" * 80)
logger.info("UPI_INWARD File Processing Scheduler Started")
logger.info(f"Poll Interval: {self.config.poll_interval_minutes} minutes")
logger.info(f"Bank Codes: {', '.join(self.config.bank_codes)}")
logger.info("=" * 80)
try:
if not self.initialize_database():
logger.error("Failed to initialize database. Exiting.")
return
except SystemExit as e:
logger.error(f"Fatal error: {e}")
raise
poll_interval_seconds = self.config.poll_interval_minutes * 60
while self.running:
try:
self.run_processing_cycle()
except Exception as e:
logger.error(f"Unexpected error in processing cycle: {e}", exc_info=True)
if self.running:
logger.info(f"Waiting {self.config.poll_interval_minutes} minutes until next cycle...")
time.sleep(poll_interval_seconds)
logger.info("Scheduler shutdown complete")
def main():
setup_logging()
scheduler = Scheduler()
scheduler.run()
if __name__ == '__main__':
main()