Files
FitTrack_GarminSync/specs/004-single-sync-job.md

5.0 KiB

004-single-sync-job: Simplify Sync Job Management with Progress Tracking

Goal

To simplify the synchronization job management by allowing only one sync job to run at a time, and to provide progress tracking for this single active sync job via a polling API. This aligns with the system's single-user nature while offering better user feedback.

Motivation

The current system is designed for a single user. While the previous iteration aimed to remove all job management complexity, the need for user feedback on ongoing sync operations necessitates a simplified progress tracking mechanism. This approach avoids a full-fledged job queue and ID system but still provides visibility into the single active sync.

Proposed Changes

1. Reintroduction of a Simplified Sync Job Model

  • Define SyncJob Model: Reintroduce a Pydantic model for SyncJob (e.g., in a new backend/src/sync_status.py file or similar). This model will represent the state of the single active sync job and will include fields such as:
    • status: str (e.g., "idle", "in_progress", "completed", "failed")
    • progress: float (0.0 to 1.0)
    • start_time: datetime
    • end_time: Optional[datetime]
    • error_message: Optional[str]
    • job_type: Optional[str] (e.g., "activities", "health", "workouts")

2. Introduce CurrentSyncJobManager

  • Create CurrentSyncJobManager: Implement a singleton class or a global object (e.g., in backend/src/sync_manager.py) to manage the state of the SyncJob. This manager will hold the single SyncJob instance and provide methods for its lifecycle.
    • start_sync(job_type: str) -> SyncJob: Initializes a new SyncJob with "in_progress" status and the given type. Sets the start_time. Returns the SyncJob instance.
    • update_progress(progress: float, details: Optional[str] = None): Updates the progress and optionally details of the current SyncJob.
    • complete_sync(): Sets the status to "completed" and end_time for the current SyncJob.
    • fail_sync(error_message: str): Sets the status to "failed", error_message, and end_time for the current SyncJob.
    • get_current_sync_status() -> SyncJob: Returns the current SyncJob instance.
    • is_sync_active() -> bool: Returns True if a sync is currently "in_progress", False otherwise.

3. Modification of Sync Service Functions

  • The _in_background functions in backend/src/services/garmin_health_service.py, backend/src/services/garmin_activity_service.py, and backend/src/services/garmin_workout_service.py will be modified:
    • They will no longer accept a job_id parameter.
    • Instead, they will receive the SyncJob instance (or a reference to the CurrentSyncJobManager) for the current operation.
    • They will use the CurrentSyncJobManager's update_progress, complete_sync, and fail_sync methods to report their status.

4. Modification of API Endpoints (backend/src/api/garmin_sync.py)

  • Remove job_store and SyncJob imports from the old system.
  • Import CurrentSyncJobManager and SyncJob from the new system.
  • Remove /status/{job_id} endpoint: This endpoint is no longer needed as there are no individual job IDs to query.
  • Modify sync initiation endpoints (/garmin/activities, /garmin/workouts, /garmin/health):
    • Before initiating a sync, check CurrentSyncJobManager.is_sync_active(). If True, return an error response (e.g., 409 Conflict) indicating that a sync is already in progress.
    • Call CurrentSyncJobManager.start_sync(job_type="...") to initialize the sync job.
    • Pass the SyncJob instance (or a reference to the CurrentSyncJobManager) to the background task.
    • Change the response_model to return the initial SyncJob status or a simple success message.
  • Add New API Endpoint for Status Polling:
    • GET /garmin/sync/status:
      • Response Model: SyncJob
      • Description: Returns the current status of the single active sync job. If no sync is active, it returns an "idle" status SyncJob.

5. Update Dependencies and Main Application

  • backend/src/dependencies.py: Remove any references to the old job_store and SyncStatusService.
  • backend/src/main.py: Ensure the CurrentSyncJobManager is properly initialized and accessible (e.g., as a global or via dependency injection if preferred).

Impact

  • Progress Tracking: Users can now poll a dedicated API endpoint to get real-time progress updates for the single active sync job.
  • Clearer State: The system's state regarding sync operations is more transparent.
  • Controlled Concurrency: Only one sync operation can run at a time, preventing resource contention in a single-user environment.
  • Simplified API: No need to manage multiple job IDs. The status endpoint always refers to the current operation.
  • Minimal Overhead: Avoids the complexity of a full-blown job queue and distributed job management system, suitable for a single-user application.