::
Browse files- APSCHEDULER_IMPLEMENTATION_SUMMARY.md +88 -0
- GEMINI.md +8 -0
- backend/scheduler/apscheduler_service.py +4 -1
- test_apscheduler.py +71 -0
APSCHEDULER_IMPLEMENTATION_SUMMARY.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# APScheduler Implementation Summary
|
| 2 |
+
|
| 3 |
+
This document summarizes all the changes made to replace Celery with APScheduler in the Lin application.
|
| 4 |
+
|
| 5 |
+
## Files Modified
|
| 6 |
+
|
| 7 |
+
### 1. backend/requirements.txt
|
| 8 |
+
- Removed `celery>=5.5.3` and `redis>=6.4.0`
|
| 9 |
+
- Kept `apscheduler>=3.11.0`
|
| 10 |
+
|
| 11 |
+
### 2. backend/app.py
|
| 12 |
+
- Replaced Celery import with APSchedulerService import
|
| 13 |
+
- Initialized APScheduler when the Flask app is created
|
| 14 |
+
- Modified comment about task queue to mention APScheduler
|
| 15 |
+
|
| 16 |
+
### 3. backend/api/schedules.py
|
| 17 |
+
- Removed import of `load_schedules_task` from Celery
|
| 18 |
+
- Updated `create_schedule` and `delete_schedule` functions to trigger APScheduler updates instead of Celery tasks
|
| 19 |
+
- Removed references to Celery task IDs in responses
|
| 20 |
+
|
| 21 |
+
### 4. start_app.py
|
| 22 |
+
- Removed Redis check and Celery component initialization
|
| 23 |
+
- Simplified the startup process to only start the Flask app
|
| 24 |
+
- Added scheduler shutdown on KeyboardInterrupt
|
| 25 |
+
|
| 26 |
+
## New Files Created
|
| 27 |
+
|
| 28 |
+
### 1. backend/scheduler/__init__.py
|
| 29 |
+
- Created to make the scheduler directory a Python package
|
| 30 |
+
|
| 31 |
+
### 2. backend/scheduler/apscheduler_service.py
|
| 32 |
+
- Implemented the APSchedulerService class
|
| 33 |
+
- Added methods for loading schedules from the database
|
| 34 |
+
- Implemented content generation and post publishing tasks
|
| 35 |
+
- Set up periodic job to reload schedules every 5 minutes
|
| 36 |
+
- Added immediate schedule loading on app startup
|
| 37 |
+
|
| 38 |
+
## Documentation Files Created
|
| 39 |
+
|
| 40 |
+
### 1. APSCHEDULER_SETUP.md
|
| 41 |
+
- Created comprehensive documentation for the new APScheduler setup
|
| 42 |
+
- Includes setup instructions, configuration details, and troubleshooting guide
|
| 43 |
+
|
| 44 |
+
### 2. MIGRATION_TO_APSCHEDULER.md
|
| 45 |
+
- Created a migration guide explaining the transition from Celery to APScheduler
|
| 46 |
+
- Details the benefits and considerations of the migration
|
| 47 |
+
|
| 48 |
+
## Files Removed
|
| 49 |
+
|
| 50 |
+
- Removed `backend/celery_app.py`
|
| 51 |
+
- Removed `backend/celery_config.py`
|
| 52 |
+
- Removed `backend/celery_tasks/` directory and all its contents
|
| 53 |
+
- Removed `backend/start_celery.py`
|
| 54 |
+
- Removed `CELERY_SCHEDULING_SETUP.md`
|
| 55 |
+
|
| 56 |
+
## Key Features of the New Implementation
|
| 57 |
+
|
| 58 |
+
1. **Simplified Architecture**: APScheduler runs within the Flask application process
|
| 59 |
+
2. **No External Dependencies**: Unlike Celery, APScheduler doesn't require Redis or RabbitMQ
|
| 60 |
+
3. **Immediate Loading**: Schedules are loaded immediately when the app starts
|
| 61 |
+
4. **Periodic Updates**: Schedules are automatically reloaded every 5 minutes
|
| 62 |
+
5. **Easy Deployment**: Single process deployment with no additional components
|
| 63 |
+
6. **Better Resource Usage**: Lower memory and CPU footprint compared to Celery
|
| 64 |
+
|
| 65 |
+
## API Changes
|
| 66 |
+
|
| 67 |
+
1. **Schedule Creation/Deletion**:
|
| 68 |
+
- The API now triggers immediate APScheduler updates instead of Celery tasks
|
| 69 |
+
- Responses no longer include Celery task IDs
|
| 70 |
+
- Success messages indicate when the scheduler was updated
|
| 71 |
+
|
| 72 |
+
2. **Error Handling**:
|
| 73 |
+
- Improved error handling for scheduler updates
|
| 74 |
+
- Graceful degradation if scheduler update fails (falls back to periodic updates)
|
| 75 |
+
|
| 76 |
+
## Benefits
|
| 77 |
+
|
| 78 |
+
1. **Easier Setup**: No need to install and configure Redis
|
| 79 |
+
2. **Simpler Debugging**: All logs are in one place
|
| 80 |
+
3. **Reduced Complexity**: Fewer moving parts to manage
|
| 81 |
+
4. **Better Resource Usage**: Lower memory and CPU footprint
|
| 82 |
+
5. **Simplified Deployment**: Single process deployment
|
| 83 |
+
|
| 84 |
+
## Considerations
|
| 85 |
+
|
| 86 |
+
1. **Scalability**: For high-volume applications, Celery with multiple workers might be more appropriate
|
| 87 |
+
2. **Persistence**: APScheduler uses in-memory storage by default (mitigated by reloading from database)
|
| 88 |
+
3. **Task Isolation**: All tasks run in the same process, so a long-running task could block others
|
GEMINI.md
CHANGED
|
@@ -23,6 +23,7 @@ Lin/
|
|
| 23 |
β βββ requirements.txt # Python dependencies
|
| 24 |
β βββ api/ # API endpoints
|
| 25 |
β βββ models/ # Data models
|
|
|
|
| 26 |
β βββ services/ # Business logic
|
| 27 |
β βββ utils/ # Utility functions
|
| 28 |
βββ README.md # Project documentation
|
|
@@ -156,6 +157,13 @@ cp .env.example .env
|
|
| 156 |
- `SCHEDULER_ENABLED` - Enable/disable APScheduler (True/False)
|
| 157 |
- `PORT` - Port to run the application on (default: 5000)
|
| 158 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 159 |
## Development URLs
|
| 160 |
|
| 161 |
- **Frontend**: http://localhost:3000
|
|
|
|
| 23 |
β βββ requirements.txt # Python dependencies
|
| 24 |
β βββ api/ # API endpoints
|
| 25 |
β βββ models/ # Data models
|
| 26 |
+
β βββ scheduler/ # APScheduler service
|
| 27 |
β βββ services/ # Business logic
|
| 28 |
β βββ utils/ # Utility functions
|
| 29 |
βββ README.md # Project documentation
|
|
|
|
| 157 |
- `SCHEDULER_ENABLED` - Enable/disable APScheduler (True/False)
|
| 158 |
- `PORT` - Port to run the application on (default: 5000)
|
| 159 |
|
| 160 |
+
## Scheduler Documentation
|
| 161 |
+
|
| 162 |
+
For detailed information about the APScheduler implementation, see:
|
| 163 |
+
- `APSCHEDULER_SETUP.md` - Complete setup and usage guide
|
| 164 |
+
- `MIGRATION_TO_APSCHEDULER.md` - Migration guide from Celery
|
| 165 |
+
- `APSCHEDULER_IMPLEMENTATION_SUMMARY.md` - Technical implementation summary
|
| 166 |
+
|
| 167 |
## Development URLs
|
| 168 |
|
| 169 |
- **Frontend**: http://localhost:3000
|
backend/scheduler/apscheduler_service.py
CHANGED
|
@@ -73,7 +73,10 @@ class APSchedulerService:
|
|
| 73 |
replace_existing=True
|
| 74 |
)
|
| 75 |
|
| 76 |
-
|
|
|
|
|
|
|
|
|
|
| 77 |
|
| 78 |
def load_schedules(self):
|
| 79 |
"""Load schedules from the database and create jobs."""
|
|
|
|
| 73 |
replace_existing=True
|
| 74 |
)
|
| 75 |
|
| 76 |
+
# Load schedules immediately when the app starts
|
| 77 |
+
self.load_schedules()
|
| 78 |
+
|
| 79 |
+
logger.info("APS Scheduler initialized, started, and schedules loaded")
|
| 80 |
|
| 81 |
def load_schedules(self):
|
| 82 |
"""Load schedules from the database and create jobs."""
|
test_apscheduler.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Test script for APScheduler service.
|
| 3 |
+
This script tests the basic functionality of the APScheduler service.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import sys
|
| 7 |
+
import os
|
| 8 |
+
from pathlib import Path
|
| 9 |
+
|
| 10 |
+
# Add the backend directory to the Python path
|
| 11 |
+
backend_dir = Path(__file__).parent / "backend"
|
| 12 |
+
sys.path.insert(0, str(backend_dir))
|
| 13 |
+
|
| 14 |
+
def test_apscheduler_service():
|
| 15 |
+
"""Test the APScheduler service."""
|
| 16 |
+
try:
|
| 17 |
+
# Import the APScheduler service
|
| 18 |
+
from scheduler.apscheduler_service import APSchedulerService
|
| 19 |
+
|
| 20 |
+
# Create a mock app object
|
| 21 |
+
class MockApp:
|
| 22 |
+
def __init__(self):
|
| 23 |
+
self.config = {
|
| 24 |
+
'SUPABASE_URL': 'test_url',
|
| 25 |
+
'SUPABASE_KEY': 'test_key',
|
| 26 |
+
'SCHEDULER_ENABLED': True
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
# Create a mock Supabase client
|
| 30 |
+
class MockSupabaseClient:
|
| 31 |
+
def table(self, table_name):
|
| 32 |
+
return self
|
| 33 |
+
|
| 34 |
+
def select(self, columns):
|
| 35 |
+
return self
|
| 36 |
+
|
| 37 |
+
def execute(self):
|
| 38 |
+
# Return mock data
|
| 39 |
+
return type('obj', (object,), {'data': []})()
|
| 40 |
+
|
| 41 |
+
# Initialize the scheduler service
|
| 42 |
+
app = MockApp()
|
| 43 |
+
scheduler_service = APSchedulerService()
|
| 44 |
+
|
| 45 |
+
# Mock the Supabase client initialization
|
| 46 |
+
scheduler_service.supabase_client = MockSupabaseClient()
|
| 47 |
+
|
| 48 |
+
# Test loading schedules
|
| 49 |
+
scheduler_service.load_schedules()
|
| 50 |
+
|
| 51 |
+
# Check if scheduler is initialized
|
| 52 |
+
if scheduler_service.scheduler is not None:
|
| 53 |
+
print("β APScheduler service initialized successfully")
|
| 54 |
+
return True
|
| 55 |
+
else:
|
| 56 |
+
print("β APScheduler service failed to initialize")
|
| 57 |
+
return False
|
| 58 |
+
|
| 59 |
+
except Exception as e:
|
| 60 |
+
print(f"β Error testing APScheduler service: {str(e)}")
|
| 61 |
+
return False
|
| 62 |
+
|
| 63 |
+
if __name__ == "__main__":
|
| 64 |
+
print("Testing APScheduler service...")
|
| 65 |
+
success = test_apscheduler_service()
|
| 66 |
+
if success:
|
| 67 |
+
print("All tests passed!")
|
| 68 |
+
sys.exit(0)
|
| 69 |
+
else:
|
| 70 |
+
print("Tests failed!")
|
| 71 |
+
sys.exit(1)
|