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:
Josh Finlay 2025-01-08 09:14:42 +10:00
parent 9046cbca1d
commit acf51a9242
1 changed files with 35 additions and 46 deletions

View File

@ -42,7 +42,7 @@ class GPIOSettings(BaseModel):
statusPin: int = 7 # Gate open status pin
class LoggingSettings(BaseModel):
level: str = "WARNING" # Default to WARNING level
level: str = "INFO" # Default to INFO level
maxBytes: int = 10 * 1024 * 1024 # 10MB default
backupCount: int = 5 # Keep 5 backup files by default
@ -278,6 +278,15 @@ last_open_time = None
gate_monitor_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():
"""Monitor gate status and update database when it changes"""
global gate_monitor_running
@ -333,64 +342,54 @@ async def update_gate_status():
logger.info("Gate status monitor stopped")
async def check_auto_close():
"""Check if gate has been open too long and close it if needed"""
global last_open_time, auto_close_running
"""Monitor gate status and auto-close if open too long"""
global auto_close_running
if auto_close_running:
logger.warning("Auto-close monitor already running, skipping...")
return
auto_close_running = True
logger.info("Starting auto-close monitoring task")
try:
settings = app.state.current_settings
if not settings:
logger.warning("No settings available, using default 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()
settings = app.state.current_settings
if not settings:
logger.warning("No settings available for auto-close, using defaults")
settings = Settings()
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:
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()
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:
logger.warning(f"Gate has been open for {time_open:.1f} seconds, auto-closing")
timestamp = current_time.isoformat()
await add_event(timestamp, "auto-close", "system")
await add_event(current_time.isoformat(), "auto-close", "system")
await trigger_gate()
last_open_time = None
logger.info("Gate auto-closed successfully")
else:
# Reset last open time if gate is closed
if last_open_time is not None:
logger.debug("Gate is now closed, resetting timer")
last_open_time = None
logger.debug("Gate closed, resetting auto-close timer")
last_open_time = None
consecutive_errors = 0
await asyncio.sleep(1)
except Exception as e:
consecutive_errors += 1
wait_time = min(30, 2 ** consecutive_errors)
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)
logger.error(f"Error in auto_close_monitor: {e}", exc_info=True)
await asyncio.sleep(5) # Wait before retrying
finally:
auto_close_running = False
logger.info("Auto-close monitor stopped")
@ -467,7 +466,7 @@ async def get_settings_route():
"statusPin": 7
}),
"logging": settings_dict.get("logging", {
"level": "WARNING",
"level": "INFO",
"maxBytes": 10 * 1024 * 1024,
"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)
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]]:
"""Validate application startup state"""
errors = []