205 lines
6.1 KiB
Python
205 lines
6.1 KiB
Python
"""
|
|
Job server for managing background job publishing and status tracking.
|
|
|
|
This module provides the JobServer class for queuing various types of jobs
|
|
using FastStream Redis broker and tracking their status in the database.
|
|
"""
|
|
|
|
import uuid
|
|
import logging
|
|
from datetime import datetime
|
|
from typing import Dict, Any, Optional
|
|
from faststream.redis import RedisBroker
|
|
from adapters.sqlite.database import get_db
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class JobServer:
|
|
"""Server for managing background job operations."""
|
|
|
|
def __init__(self, broker: RedisBroker):
|
|
"""
|
|
Initialize JobServer with Redis broker.
|
|
|
|
Args:
|
|
broker: FastStream Redis broker instance
|
|
"""
|
|
self.broker = broker
|
|
self.db = get_db
|
|
|
|
async def queue_export_job(self, configuration_id: int) -> str:
|
|
"""
|
|
Queue an export job for processing.
|
|
|
|
Args:
|
|
configuration_id: ID of the export configuration to process
|
|
|
|
Returns:
|
|
job_id: Unique identifier for the queued job
|
|
"""
|
|
job_id = str(uuid.uuid4())
|
|
job_data = {
|
|
"job_id": job_id,
|
|
"job_type": "export",
|
|
"configuration_id": configuration_id,
|
|
"created_at": datetime.utcnow().isoformat(),
|
|
"status": "queued"
|
|
}
|
|
|
|
try:
|
|
# Create job record in database
|
|
await self._create_job_record(job_data)
|
|
|
|
# Publish to export-jobs channel
|
|
await self.broker.publish(job_data, "export-jobs")
|
|
|
|
logger.info(f"Export job {job_id} queued successfully")
|
|
return job_id
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to queue export job: {str(e)}")
|
|
await self._update_job_status(job_id, "failed", error_message=str(e))
|
|
raise
|
|
|
|
async def queue_sync_job(
|
|
self,
|
|
entity_type: str,
|
|
limit: Optional[int] = None,
|
|
page: Optional[int] = None,
|
|
**kwargs
|
|
) -> str:
|
|
"""
|
|
Queue a data synchronization job.
|
|
|
|
Args:
|
|
entity_type: Type of entity to sync (deals, contacts, companies, etc.)
|
|
limit: Maximum number of records to sync
|
|
page: Page number for pagination
|
|
**kwargs: Additional parameters for the sync job
|
|
|
|
Returns:
|
|
job_id: Unique identifier for the queued job
|
|
"""
|
|
job_id = str(uuid.uuid4())
|
|
sync_data = {
|
|
"job_id": job_id,
|
|
"job_type": "sync",
|
|
"entity_type": entity_type,
|
|
"parameters": {
|
|
"limit": limit,
|
|
"page": page,
|
|
**kwargs
|
|
},
|
|
"created_at": datetime.utcnow().isoformat(),
|
|
"status": "queued"
|
|
}
|
|
|
|
try:
|
|
# Create job record in database
|
|
await self._create_job_record(sync_data)
|
|
|
|
# Publish to sync-jobs channel
|
|
await self.broker.publish(sync_data, "sync-jobs")
|
|
|
|
logger.info(f"Sync job {job_id} for {entity_type} queued successfully")
|
|
return job_id
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to queue sync job: {str(e)}")
|
|
await self._update_job_status(job_id, "failed", error_message=str(e))
|
|
raise
|
|
|
|
async def schedule_refresh_job(self, entity_type: str) -> None:
|
|
"""
|
|
Schedule periodic data refresh for an entity type.
|
|
|
|
Args:
|
|
entity_type: Type of entity to refresh
|
|
"""
|
|
try:
|
|
# Publish to refresh-jobs channel
|
|
await self.broker.publish(entity_type, "refresh-jobs")
|
|
|
|
logger.info(f"Refresh job for {entity_type} scheduled successfully")
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to schedule refresh job for {entity_type}: {str(e)}")
|
|
raise
|
|
|
|
async def get_job_status(self, job_id: str) -> Optional[Dict[str, Any]]:
|
|
"""
|
|
Get the status of a specific job.
|
|
|
|
Args:
|
|
job_id: Unique identifier of the job
|
|
|
|
Returns:
|
|
Job status information or None if not found
|
|
"""
|
|
try:
|
|
# TODO: Implement database query to get job status
|
|
# This would query the export_jobs table
|
|
pass
|
|
except Exception as e:
|
|
logger.error(f"Failed to get job status for {job_id}: {str(e)}")
|
|
return None
|
|
|
|
async def list_jobs(
|
|
self,
|
|
status: Optional[str] = None,
|
|
job_type: Optional[str] = None,
|
|
limit: int = 20,
|
|
offset: int = 0
|
|
) -> Dict[str, Any]:
|
|
"""
|
|
List jobs with optional filtering.
|
|
|
|
Args:
|
|
status: Filter by job status (pending, running, completed, failed)
|
|
job_type: Filter by job type (export, sync)
|
|
limit: Maximum number of jobs to return
|
|
offset: Number of jobs to skip
|
|
|
|
Returns:
|
|
Dictionary containing jobs list and pagination info
|
|
"""
|
|
try:
|
|
# TODO: Implement database query to list jobs
|
|
# This would query the export_jobs table with filters
|
|
pass
|
|
except Exception as e:
|
|
logger.error(f"Failed to list jobs: {str(e)}")
|
|
return {"jobs": [], "total": 0}
|
|
|
|
async def _create_job_record(self, job_data: Dict[str, Any]) -> None:
|
|
"""
|
|
Create a job record in the database.
|
|
|
|
Args:
|
|
job_data: Job information to store
|
|
"""
|
|
# TODO: Implement database insertion
|
|
# This would insert into the export_jobs table
|
|
pass
|
|
|
|
async def _update_job_status(
|
|
self,
|
|
job_id: str,
|
|
status: str,
|
|
error_message: Optional[str] = None,
|
|
**kwargs
|
|
) -> None:
|
|
"""
|
|
Update job status in the database.
|
|
|
|
Args:
|
|
job_id: Unique identifier of the job
|
|
status: New status (pending, running, completed, failed)
|
|
error_message: Error message if status is failed
|
|
**kwargs: Additional fields to update
|
|
"""
|
|
# TODO: Implement database update
|
|
# This would update the export_jobs table
|
|
pass
|