152 lines
4.0 KiB
Markdown
152 lines
4.0 KiB
Markdown
# Task Management Service - Implementation Summary
|
|
|
|
## Overview
|
|
Implemented a thread pool-based background task service for EU-Utility that replaces the need for plugins to create their own QThreads.
|
|
|
|
## Files Created
|
|
|
|
### 1. `core/tasks.py`
|
|
The core TaskManager implementation with:
|
|
|
|
- **Singleton TaskManager class** - Shared across the application
|
|
- **ThreadPoolExecutor** - Configurable max workers (default: 4)
|
|
- **Task priority levels** - HIGH, NORMAL, LOW
|
|
- **Task scheduling**:
|
|
- `run_in_thread()` - Immediate background execution
|
|
- `run_later()` - Delayed execution (ms)
|
|
- `run_periodic()` - Repeating execution at interval
|
|
- **Callback support** - `on_complete`, `on_error`
|
|
- **Task ID tracking** - UUID-based unique IDs
|
|
- **Graceful shutdown** - Wait for tasks or cancel with timeout
|
|
- **Qt signal integration** - Thread-safe UI updates
|
|
|
|
Key signals:
|
|
- `task_completed` - (task_id, result)
|
|
- `task_failed` - (task_id, error_message)
|
|
- `task_started` - (task_id)
|
|
- `task_cancelled` - (task_id)
|
|
- `task_periodic` - (task_id, iteration, result)
|
|
|
|
## Files Modified
|
|
|
|
### 2. `core/plugin_api.py`
|
|
Added to PluginAPI:
|
|
- `register_task_service()` - Register TaskManager instance
|
|
- `run_in_background()` - Run function in thread pool
|
|
- `schedule_task()` - Delayed/periodic task scheduling
|
|
- `cancel_task()` - Cancel pending/running task
|
|
- `get_task_status()` - Query task status
|
|
- `wait_for_task()` - Wait for completion
|
|
- `connect_task_signal()` - Connect to Qt signals
|
|
|
|
### 3. `plugins/base_plugin.py`
|
|
Added to BasePlugin:
|
|
- `run_in_background()` - Background task execution
|
|
- `schedule_task()` - Delayed/periodic scheduling
|
|
- `cancel_task()` - Task cancellation
|
|
- `connect_task_signals()` - Batch signal connection
|
|
|
|
### 4. `core/main.py`
|
|
Changes:
|
|
- Import `get_task_manager` from tasks module
|
|
- Initialize TaskManager in `_setup_api_services()`
|
|
- Register task service with API
|
|
- Graceful shutdown in `quit()` - waits for tasks (30s timeout)
|
|
|
|
## Usage Examples
|
|
|
|
### Simple Background Task
|
|
```python
|
|
def heavy_calculation(data):
|
|
return process(data)
|
|
|
|
task_id = self.run_in_background(
|
|
heavy_calculation,
|
|
large_dataset,
|
|
priority='high',
|
|
on_complete=lambda result: print(f"Done: {result}"),
|
|
on_error=lambda e: print(f"Error: {e}")
|
|
)
|
|
```
|
|
|
|
### Delayed Task
|
|
```python
|
|
task_id = self.schedule_task(
|
|
delay_ms=5000, # 5 seconds
|
|
func=lambda: print("Hello!"),
|
|
on_complete=lambda _: print("Complete")
|
|
)
|
|
```
|
|
|
|
### Periodic Task
|
|
```python
|
|
task_id = self.schedule_task(
|
|
delay_ms=0,
|
|
func=fetch_data,
|
|
periodic=True,
|
|
interval_ms=30000, # Every 30 seconds
|
|
on_complete=lambda data: update_ui(data)
|
|
)
|
|
|
|
# Cancel later
|
|
self.cancel_task(task_id)
|
|
```
|
|
|
|
### UI Updates (Thread-Safe)
|
|
```python
|
|
def initialize(self):
|
|
# Connect signals once
|
|
self.connect_task_signals(
|
|
on_completed=self._on_done,
|
|
on_failed=self._on_error
|
|
)
|
|
|
|
def start_work(self):
|
|
# Run in background
|
|
self.run_in_background(
|
|
self.process_data,
|
|
priority='normal'
|
|
)
|
|
|
|
def _on_done(self, task_id, result):
|
|
# Runs in main thread - safe to update UI!
|
|
self.status_label.setText(f"Complete: {result}")
|
|
|
|
def _on_error(self, task_id, error):
|
|
self.status_label.setText(f"Error: {error}")
|
|
```
|
|
|
|
## Benefits
|
|
|
|
1. **No more QThreads** - Plugins use shared thread pool
|
|
2. **Qt signal integration** - Thread-safe UI updates
|
|
3. **Priority levels** - HIGH tasks run before LOW
|
|
4. **Task tracking** - Monitor and cancel tasks
|
|
5. **Graceful shutdown** - Wait for tasks on exit
|
|
6. **Error handling** - Centralized error callbacks
|
|
7. **Less code** - Simple API vs managing QThreads
|
|
|
|
## Migration Guide
|
|
|
|
**Before (with QThread):**
|
|
```python
|
|
class Worker(QThread):
|
|
finished = pyqtSignal(object)
|
|
|
|
def run(self):
|
|
result = heavy_work()
|
|
self.finished.emit(result)
|
|
|
|
worker = Worker()
|
|
worker.finished.connect(self.handle_result)
|
|
worker.start()
|
|
```
|
|
|
|
**After (with TaskManager):**
|
|
```python
|
|
task_id = self.run_in_background(
|
|
heavy_work,
|
|
on_complete=self.handle_result
|
|
)
|
|
```
|