Add POI feature and imporve the overall backend implementation
This commit is contained in:
154
services/external/app/models/poi_refresh_job.py
vendored
Normal file
154
services/external/app/models/poi_refresh_job.py
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
"""
|
||||
POI Refresh Job Model
|
||||
|
||||
Tracks background jobs for periodic POI context refresh.
|
||||
"""
|
||||
|
||||
from sqlalchemy import Column, String, DateTime, Integer, Boolean, Text, Float
|
||||
from sqlalchemy.dialects.postgresql import UUID, JSONB
|
||||
from datetime import datetime, timezone
|
||||
import uuid
|
||||
|
||||
from app.core.database import Base
|
||||
|
||||
|
||||
class POIRefreshJob(Base):
|
||||
"""
|
||||
POI Refresh Background Job Model
|
||||
|
||||
Tracks periodic POI context refresh jobs for all tenants.
|
||||
Jobs run on a configurable schedule (default: 180 days).
|
||||
"""
|
||||
|
||||
__tablename__ = "poi_refresh_jobs"
|
||||
|
||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
|
||||
|
||||
# Job scheduling
|
||||
scheduled_at = Column(
|
||||
DateTime(timezone=True),
|
||||
nullable=False,
|
||||
index=True,
|
||||
comment="When this job was scheduled"
|
||||
)
|
||||
started_at = Column(
|
||||
DateTime(timezone=True),
|
||||
nullable=True,
|
||||
comment="When job execution started"
|
||||
)
|
||||
completed_at = Column(
|
||||
DateTime(timezone=True),
|
||||
nullable=True,
|
||||
comment="When job execution completed"
|
||||
)
|
||||
|
||||
# Job status
|
||||
status = Column(
|
||||
String(50),
|
||||
nullable=False,
|
||||
default="pending",
|
||||
index=True,
|
||||
comment="Job status: pending, running, completed, failed"
|
||||
)
|
||||
|
||||
# Job execution details
|
||||
attempt_count = Column(
|
||||
Integer,
|
||||
nullable=False,
|
||||
default=0,
|
||||
comment="Number of execution attempts"
|
||||
)
|
||||
max_attempts = Column(
|
||||
Integer,
|
||||
nullable=False,
|
||||
default=3,
|
||||
comment="Maximum number of retry attempts"
|
||||
)
|
||||
|
||||
# Location data (cached for job execution)
|
||||
latitude = Column(
|
||||
Float,
|
||||
nullable=False,
|
||||
comment="Bakery latitude for POI detection"
|
||||
)
|
||||
longitude = Column(
|
||||
Float,
|
||||
nullable=False,
|
||||
comment="Bakery longitude for POI detection"
|
||||
)
|
||||
|
||||
# Results
|
||||
pois_detected = Column(
|
||||
Integer,
|
||||
nullable=True,
|
||||
comment="Number of POIs detected in this refresh"
|
||||
)
|
||||
changes_detected = Column(
|
||||
Boolean,
|
||||
default=False,
|
||||
comment="Whether significant changes were detected"
|
||||
)
|
||||
change_summary = Column(
|
||||
JSONB,
|
||||
nullable=True,
|
||||
comment="Summary of changes detected"
|
||||
)
|
||||
|
||||
# Error handling
|
||||
error_message = Column(
|
||||
Text,
|
||||
nullable=True,
|
||||
comment="Error message if job failed"
|
||||
)
|
||||
error_details = Column(
|
||||
JSONB,
|
||||
nullable=True,
|
||||
comment="Detailed error information"
|
||||
)
|
||||
|
||||
# Next execution
|
||||
next_scheduled_at = Column(
|
||||
DateTime(timezone=True),
|
||||
nullable=True,
|
||||
index=True,
|
||||
comment="When next refresh should be scheduled"
|
||||
)
|
||||
|
||||
# Metadata
|
||||
created_at = Column(
|
||||
DateTime(timezone=True),
|
||||
nullable=False,
|
||||
default=lambda: datetime.now(timezone.utc)
|
||||
)
|
||||
updated_at = Column(
|
||||
DateTime(timezone=True),
|
||||
nullable=False,
|
||||
default=lambda: datetime.now(timezone.utc),
|
||||
onupdate=lambda: datetime.now(timezone.utc)
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return (
|
||||
f"<POIRefreshJob(id={self.id}, tenant_id={self.tenant_id}, "
|
||||
f"status={self.status}, scheduled_at={self.scheduled_at})>"
|
||||
)
|
||||
|
||||
@property
|
||||
def is_overdue(self) -> bool:
|
||||
"""Check if job is overdue for execution"""
|
||||
if self.status in ("completed", "running"):
|
||||
return False
|
||||
return datetime.now(timezone.utc) > self.scheduled_at
|
||||
|
||||
@property
|
||||
def can_retry(self) -> bool:
|
||||
"""Check if job can be retried"""
|
||||
return self.attempt_count < self.max_attempts
|
||||
|
||||
@property
|
||||
def duration_seconds(self) -> float | None:
|
||||
"""Calculate job duration in seconds"""
|
||||
if self.started_at and self.completed_at:
|
||||
return (self.completed_at - self.started_at).total_seconds()
|
||||
return None
|
||||
Reference in New Issue
Block a user