fix: background task initialization
- Fixed double-start issue with background tasks - Improved task error handling - Added more descriptive logging - Made auto-close logic more consistent
This commit is contained in:
parent
9046cbca1d
commit
acf51a9242
|
|
@ -42,7 +42,7 @@ class GPIOSettings(BaseModel):
|
||||||
statusPin: int = 7 # Gate open status pin
|
statusPin: int = 7 # Gate open status pin
|
||||||
|
|
||||||
class LoggingSettings(BaseModel):
|
class LoggingSettings(BaseModel):
|
||||||
level: str = "WARNING" # Default to WARNING level
|
level: str = "INFO" # Default to INFO level
|
||||||
maxBytes: int = 10 * 1024 * 1024 # 10MB default
|
maxBytes: int = 10 * 1024 * 1024 # 10MB default
|
||||||
backupCount: int = 5 # Keep 5 backup files by default
|
backupCount: int = 5 # Keep 5 backup files by default
|
||||||
|
|
||||||
|
|
@ -278,6 +278,15 @@ last_open_time = None
|
||||||
gate_monitor_running = False
|
gate_monitor_running = False
|
||||||
auto_close_running = False
|
auto_close_running = False
|
||||||
|
|
||||||
|
async def start_background_tasks():
|
||||||
|
"""Start all background monitoring tasks"""
|
||||||
|
logger.info("Starting background tasks...")
|
||||||
|
|
||||||
|
# Don't set global flags here, let the tasks set them
|
||||||
|
app.state.status_task = asyncio.create_task(update_gate_status())
|
||||||
|
app.state.auto_close_task = asyncio.create_task(check_auto_close())
|
||||||
|
logger.info("Background tasks started")
|
||||||
|
|
||||||
async def update_gate_status():
|
async def update_gate_status():
|
||||||
"""Monitor gate status and update database when it changes"""
|
"""Monitor gate status and update database when it changes"""
|
||||||
global gate_monitor_running
|
global gate_monitor_running
|
||||||
|
|
@ -333,64 +342,54 @@ async def update_gate_status():
|
||||||
logger.info("Gate status monitor stopped")
|
logger.info("Gate status monitor stopped")
|
||||||
|
|
||||||
async def check_auto_close():
|
async def check_auto_close():
|
||||||
"""Check if gate has been open too long and close it if needed"""
|
"""Monitor gate status and auto-close if open too long"""
|
||||||
global last_open_time, auto_close_running
|
global auto_close_running
|
||||||
|
|
||||||
if auto_close_running:
|
if auto_close_running:
|
||||||
logger.warning("Auto-close monitor already running, skipping...")
|
logger.warning("Auto-close monitor already running, skipping...")
|
||||||
return
|
return
|
||||||
|
|
||||||
auto_close_running = True
|
auto_close_running = True
|
||||||
logger.info("Starting auto-close monitoring task")
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
try:
|
try:
|
||||||
settings = app.state.current_settings
|
settings = app.state.current_settings
|
||||||
if not settings:
|
if not settings:
|
||||||
logger.warning("No settings available, using default settings")
|
logger.warning("No settings available for auto-close, using defaults")
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
|
|
||||||
status_pin = settings.gpio.statusPin
|
|
||||||
consecutive_errors = 0
|
|
||||||
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
if not auto_close_running:
|
|
||||||
logger.info("Auto-close monitor stopped")
|
|
||||||
break
|
|
||||||
|
|
||||||
if GPIO.input(status_pin) == GPIO.HIGH: # Gate is open
|
|
||||||
current_time = datetime.now()
|
current_time = datetime.now()
|
||||||
|
|
||||||
|
# Check if gate is open
|
||||||
|
if gate_status.is_open:
|
||||||
|
# If this is the first time we see it open, record the time
|
||||||
|
global last_open_time
|
||||||
if last_open_time is None:
|
if last_open_time is None:
|
||||||
last_open_time = current_time
|
last_open_time = current_time
|
||||||
logger.debug("Gate opened, starting timer")
|
logger.debug("Gate opened, starting auto-close timer")
|
||||||
|
|
||||||
|
# Calculate how long it's been open
|
||||||
time_open = (current_time - last_open_time).total_seconds()
|
time_open = (current_time - last_open_time).total_seconds()
|
||||||
logger.debug(f"Gate has been open for {time_open:.1f} seconds")
|
|
||||||
|
|
||||||
|
# Auto-close if it's been open too long
|
||||||
if time_open > settings.maxOpenTimeSeconds:
|
if time_open > settings.maxOpenTimeSeconds:
|
||||||
logger.warning(f"Gate has been open for {time_open:.1f} seconds, auto-closing")
|
logger.warning(f"Gate has been open for {time_open:.1f} seconds, auto-closing")
|
||||||
timestamp = current_time.isoformat()
|
await add_event(current_time.isoformat(), "auto-close", "system")
|
||||||
|
|
||||||
await add_event(timestamp, "auto-close", "system")
|
|
||||||
|
|
||||||
await trigger_gate()
|
await trigger_gate()
|
||||||
last_open_time = None
|
last_open_time = None
|
||||||
logger.info("Gate auto-closed successfully")
|
|
||||||
else:
|
else:
|
||||||
|
# Reset last open time if gate is closed
|
||||||
if last_open_time is not None:
|
if last_open_time is not None:
|
||||||
logger.debug("Gate is now closed, resetting timer")
|
logger.debug("Gate closed, resetting auto-close timer")
|
||||||
last_open_time = None
|
last_open_time = None
|
||||||
|
|
||||||
consecutive_errors = 0
|
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
consecutive_errors += 1
|
logger.error(f"Error in auto_close_monitor: {e}", exc_info=True)
|
||||||
wait_time = min(30, 2 ** consecutive_errors)
|
await asyncio.sleep(5) # Wait before retrying
|
||||||
logger.error(f"Error in check_auto_close (attempt {consecutive_errors}): {e}", exc_info=True)
|
|
||||||
logger.warning(f"Retrying in {wait_time} seconds...")
|
|
||||||
await asyncio.sleep(wait_time)
|
|
||||||
finally:
|
finally:
|
||||||
auto_close_running = False
|
auto_close_running = False
|
||||||
logger.info("Auto-close monitor stopped")
|
logger.info("Auto-close monitor stopped")
|
||||||
|
|
@ -467,7 +466,7 @@ async def get_settings_route():
|
||||||
"statusPin": 7
|
"statusPin": 7
|
||||||
}),
|
}),
|
||||||
"logging": settings_dict.get("logging", {
|
"logging": settings_dict.get("logging", {
|
||||||
"level": "WARNING",
|
"level": "INFO",
|
||||||
"maxBytes": 10 * 1024 * 1024,
|
"maxBytes": 10 * 1024 * 1024,
|
||||||
"backupCount": 5
|
"backupCount": 5
|
||||||
})
|
})
|
||||||
|
|
@ -698,16 +697,6 @@ async def publish_mqtt_state(state: bool) -> bool:
|
||||||
logger.error(f"Failed to publish MQTT state: {e}", exc_info=True)
|
logger.error(f"Failed to publish MQTT state: {e}", exc_info=True)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
async def start_background_tasks():
|
|
||||||
"""Start all background monitoring tasks"""
|
|
||||||
logger.info("Starting background tasks...")
|
|
||||||
global gate_monitor_running, auto_close_running
|
|
||||||
gate_monitor_running = True
|
|
||||||
auto_close_running = True
|
|
||||||
app.state.status_task = asyncio.create_task(update_gate_status())
|
|
||||||
app.state.auto_close_task = asyncio.create_task(check_auto_close())
|
|
||||||
logger.info("Background tasks started")
|
|
||||||
|
|
||||||
async def validate_startup_state() -> tuple[bool, list[str]]:
|
async def validate_startup_state() -> tuple[bool, list[str]]:
|
||||||
"""Validate application startup state"""
|
"""Validate application startup state"""
|
||||||
errors = []
|
errors = []
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue