Vorläufig fertiger server
Dieser Commit ist enthalten in:
75
v2_adminpanel/migrations/README.md
Normale Datei
75
v2_adminpanel/migrations/README.md
Normale Datei
@@ -0,0 +1,75 @@
|
||||
# Database Migrations
|
||||
|
||||
## License Heartbeats Table Migration
|
||||
|
||||
### Overview
|
||||
The `create_license_heartbeats_table.sql` migration creates a partitioned table for storing real-time license validation data. This table is essential for the Live Dashboard & Analytics functionality.
|
||||
|
||||
### Features
|
||||
- Monthly partitioning for efficient data management
|
||||
- Automatic creation of current and next month partitions
|
||||
- Optimized indexes for performance
|
||||
- Foreign key relationship with licenses table
|
||||
|
||||
### Running the Migration
|
||||
|
||||
#### Option 1: Using the Python Script
|
||||
```bash
|
||||
cd /path/to/v2_adminpanel
|
||||
python apply_license_heartbeats_migration.py
|
||||
```
|
||||
|
||||
#### Option 2: Manual SQL Execution
|
||||
```bash
|
||||
psql -h postgres -U postgres -d v2_adminpanel -f migrations/create_license_heartbeats_table.sql
|
||||
```
|
||||
|
||||
#### Option 3: Docker Exec
|
||||
```bash
|
||||
docker exec -it v2_adminpanel_postgres psql -U postgres -d v2_adminpanel -f /migrations/create_license_heartbeats_table.sql
|
||||
```
|
||||
|
||||
### Verification
|
||||
After running the migration, verify the table was created:
|
||||
|
||||
```sql
|
||||
-- Check if table exists
|
||||
SELECT EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.tables
|
||||
WHERE table_name = 'license_heartbeats'
|
||||
);
|
||||
|
||||
-- List all partitions
|
||||
SELECT tablename
|
||||
FROM pg_tables
|
||||
WHERE tablename LIKE 'license_heartbeats_%'
|
||||
ORDER BY tablename;
|
||||
```
|
||||
|
||||
### Partition Management
|
||||
The system automatically creates partitions as needed. To manually create future partitions:
|
||||
|
||||
```python
|
||||
from utils.partition_helper import create_future_partitions
|
||||
import psycopg2
|
||||
|
||||
conn = psycopg2.connect(...)
|
||||
create_future_partitions(conn, 'license_heartbeats', months_ahead=6)
|
||||
```
|
||||
|
||||
### Data Retention
|
||||
Consider implementing a data retention policy to remove old partitions:
|
||||
|
||||
```sql
|
||||
-- Drop partitions older than 3 months
|
||||
DROP TABLE IF EXISTS license_heartbeats_2025_03;
|
||||
```
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
1. **Table already exists**: The migration is idempotent and will skip creation if the table exists.
|
||||
|
||||
2. **Permission denied**: Ensure the database user has CREATE privileges.
|
||||
|
||||
3. **Foreign key violation**: The licenses table must exist before running this migration.
|
||||
58
v2_adminpanel/migrations/add_june_2025_partition.sql
Normale Datei
58
v2_adminpanel/migrations/add_june_2025_partition.sql
Normale Datei
@@ -0,0 +1,58 @@
|
||||
-- Migration: Add June 2025 partition for license_heartbeats table
|
||||
-- This migration adds the missing partition for the current month (June 2025)
|
||||
|
||||
-- Check if the partition already exists before creating it
|
||||
DO $$
|
||||
BEGIN
|
||||
-- Check if the June 2025 partition exists
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM pg_tables
|
||||
WHERE tablename = 'license_heartbeats_2025_06'
|
||||
) THEN
|
||||
-- Create the June 2025 partition
|
||||
EXECUTE 'CREATE TABLE license_heartbeats_2025_06 PARTITION OF license_heartbeats
|
||||
FOR VALUES FROM (''2025-06-01'') TO (''2025-07-01'')';
|
||||
|
||||
RAISE NOTICE 'Created partition license_heartbeats_2025_06';
|
||||
ELSE
|
||||
RAISE NOTICE 'Partition license_heartbeats_2025_06 already exists';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Also create partitions for the next few months to avoid future issues
|
||||
DO $$
|
||||
DECLARE
|
||||
partition_name text;
|
||||
start_date date;
|
||||
end_date date;
|
||||
i integer;
|
||||
BEGIN
|
||||
-- Create partitions for the next 6 months
|
||||
FOR i IN 0..6 LOOP
|
||||
start_date := date_trunc('month', CURRENT_DATE + (i || ' months')::interval);
|
||||
end_date := start_date + interval '1 month';
|
||||
partition_name := 'license_heartbeats_' || to_char(start_date, 'YYYY_MM');
|
||||
|
||||
-- Check if partition already exists
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM pg_tables
|
||||
WHERE tablename = partition_name
|
||||
) THEN
|
||||
EXECUTE format('CREATE TABLE %I PARTITION OF license_heartbeats FOR VALUES FROM (%L) TO (%L)',
|
||||
partition_name, start_date, end_date);
|
||||
|
||||
RAISE NOTICE 'Created partition %', partition_name;
|
||||
END IF;
|
||||
END LOOP;
|
||||
END $$;
|
||||
|
||||
-- Verify the partitions were created
|
||||
SELECT
|
||||
schemaname,
|
||||
tablename,
|
||||
tableowner
|
||||
FROM pg_tables
|
||||
WHERE tablename LIKE 'license_heartbeats_%'
|
||||
ORDER BY tablename;
|
||||
79
v2_adminpanel/migrations/create_license_heartbeats_table.sql
Normale Datei
79
v2_adminpanel/migrations/create_license_heartbeats_table.sql
Normale Datei
@@ -0,0 +1,79 @@
|
||||
-- Migration: Create license_heartbeats partitioned table
|
||||
-- Date: 2025-06-19
|
||||
-- Description: Creates the license_heartbeats table with monthly partitioning
|
||||
|
||||
-- Create the partitioned table
|
||||
CREATE TABLE IF NOT EXISTS license_heartbeats (
|
||||
id BIGSERIAL,
|
||||
license_id INTEGER NOT NULL,
|
||||
hardware_id VARCHAR(255) NOT NULL,
|
||||
ip_address INET NOT NULL,
|
||||
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
session_data JSONB,
|
||||
PRIMARY KEY (id, timestamp),
|
||||
FOREIGN KEY (license_id) REFERENCES licenses(id) ON DELETE CASCADE
|
||||
) PARTITION BY RANGE (timestamp);
|
||||
|
||||
-- Create indexes for better query performance
|
||||
CREATE INDEX IF NOT EXISTS idx_license_heartbeats_license_id_timestamp
|
||||
ON license_heartbeats (license_id, timestamp DESC);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_license_heartbeats_timestamp
|
||||
ON license_heartbeats (timestamp DESC);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_license_heartbeats_hardware_id
|
||||
ON license_heartbeats (hardware_id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_license_heartbeats_ip_address
|
||||
ON license_heartbeats (ip_address);
|
||||
|
||||
-- Create partitions for current and next month
|
||||
DO $$
|
||||
DECLARE
|
||||
current_year INTEGER;
|
||||
current_month INTEGER;
|
||||
next_year INTEGER;
|
||||
next_month INTEGER;
|
||||
partition_name TEXT;
|
||||
start_date DATE;
|
||||
end_date DATE;
|
||||
BEGIN
|
||||
-- Get current date info
|
||||
current_year := EXTRACT(YEAR FROM CURRENT_DATE);
|
||||
current_month := EXTRACT(MONTH FROM CURRENT_DATE);
|
||||
|
||||
-- Calculate next month
|
||||
IF current_month = 12 THEN
|
||||
next_year := current_year + 1;
|
||||
next_month := 1;
|
||||
ELSE
|
||||
next_year := current_year;
|
||||
next_month := current_month + 1;
|
||||
END IF;
|
||||
|
||||
-- Create current month partition
|
||||
partition_name := 'license_heartbeats_' || current_year || '_' || LPAD(current_month::TEXT, 2, '0');
|
||||
start_date := DATE_TRUNC('month', CURRENT_DATE);
|
||||
end_date := DATE_TRUNC('month', CURRENT_DATE) + INTERVAL '1 month';
|
||||
|
||||
EXECUTE format('CREATE TABLE IF NOT EXISTS %I PARTITION OF license_heartbeats FOR VALUES FROM (%L) TO (%L)',
|
||||
partition_name, start_date, end_date);
|
||||
|
||||
-- Create next month partition
|
||||
partition_name := 'license_heartbeats_' || next_year || '_' || LPAD(next_month::TEXT, 2, '0');
|
||||
start_date := end_date;
|
||||
end_date := start_date + INTERVAL '1 month';
|
||||
|
||||
EXECUTE format('CREATE TABLE IF NOT EXISTS %I PARTITION OF license_heartbeats FOR VALUES FROM (%L) TO (%L)',
|
||||
partition_name, start_date, end_date);
|
||||
|
||||
RAISE NOTICE 'Created partitions for current and next month';
|
||||
END $$;
|
||||
|
||||
-- Add comment to the table
|
||||
COMMENT ON TABLE license_heartbeats IS 'Stores heartbeat data from license validations for real-time monitoring';
|
||||
COMMENT ON COLUMN license_heartbeats.license_id IS 'Foreign key to licenses table';
|
||||
COMMENT ON COLUMN license_heartbeats.hardware_id IS 'Hardware identifier of the device';
|
||||
COMMENT ON COLUMN license_heartbeats.ip_address IS 'IP address from which the heartbeat was sent';
|
||||
COMMENT ON COLUMN license_heartbeats.timestamp IS 'Timestamp of the heartbeat';
|
||||
COMMENT ON COLUMN license_heartbeats.session_data IS 'Additional session data in JSON format';
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren