Fix timezone handling in cluster client uptime calculation

- Store connected_at as UTC ISO string with Z suffix
- Handle datetime objects from database as UTC timestamps
- Ensure uptime calculation uses correct UTC times regardless of server timezone
parent f6cd6c06
......@@ -1656,14 +1656,15 @@ def save_cluster_client(client_id: str, token: str, hostname: str, ip_address: s
if connected_at is None:
connected_at = time.time()
# Store as Unix timestamp (float) to avoid timezone issues
connected_at_value = connected_at
# Store as ISO UTC string with Z suffix to avoid timezone issues
from datetime import datetime
connected_at_str = datetime.utcfromtimestamp(connected_at).isoformat() + 'Z'
config = get_db_config()
if config['type'] == 'mysql':
cursor.execute('''
INSERT INTO cluster_clients (client_id, token, hostname, ip_address, weight, gpu_info, available_backends, connected, connected_at, last_seen)
VALUES (?, ?, ?, ?, ?, ?, ?, 1, FROM_UNIXTIME(?), CURRENT_TIMESTAMP)
VALUES (?, ?, ?, ?, ?, ?, ?, 1, ?, CURRENT_TIMESTAMP)
ON DUPLICATE KEY UPDATE
hostname = VALUES(hostname),
ip_address = VALUES(ip_address),
......@@ -1671,16 +1672,16 @@ def save_cluster_client(client_id: str, token: str, hostname: str, ip_address: s
gpu_info = VALUES(gpu_info),
available_backends = VALUES(available_backends),
connected = 1,
connected_at = FROM_UNIXTIME(?),
connected_at = VALUES(connected_at),
last_seen = CURRENT_TIMESTAMP
''', (client_id, token, hostname, ip_address, weight, gpu_info_json, available_backends_json, connected_at_value, connected_at_value))
''', (client_id, token, hostname, ip_address, weight, gpu_info_json, available_backends_json, connected_at_str))
else:
# For SQLite
cursor.execute('''
INSERT OR REPLACE INTO cluster_clients
(client_id, token, hostname, ip_address, weight, gpu_info, available_backends, connected, connected_at, last_seen)
VALUES (?, ?, ?, ?, ?, ?, ?, 1, datetime(?, 'unixepoch'), CURRENT_TIMESTAMP)
''', (client_id, token, hostname, ip_address, weight, gpu_info_json, available_backends_json, connected_at_value))
VALUES (?, ?, ?, ?, ?, ?, ?, 1, ?, CURRENT_TIMESTAMP)
''', (client_id, token, hostname, ip_address, weight, gpu_info_json, available_backends_json, connected_at_str))
conn.commit()
success = cursor.rowcount > 0
......
......@@ -444,12 +444,23 @@ def api_cluster_nodes():
connected_at = client.get('connected_at')
if connected_at:
if isinstance(connected_at, str):
# Parse timestamp string
# Parse ISO UTC string (with Z suffix)
import datetime
connected_at = datetime.datetime.fromisoformat(connected_at.replace('Z', '+00:00')).timestamp()
if connected_at.endswith('Z'):
connected_at = datetime.datetime.fromisoformat(connected_at[:-1] + '+00:00').timestamp()
else:
# Fallback for other formats
connected_at = datetime.datetime.fromisoformat(connected_at.replace('Z', '+00:00')).timestamp()
elif hasattr(connected_at, 'timestamp'):
# datetime object
connected_at = connected_at.timestamp()
# datetime object - assume it's in UTC (make it timezone aware)
import datetime
if connected_at.tzinfo is None:
# Naive datetime, assume it's UTC
utc_dt = connected_at.replace(tzinfo=datetime.timezone.utc)
connected_at = utc_dt.timestamp()
else:
# Already timezone aware
connected_at = connected_at.timestamp()
# If it's already a float/int timestamp, use it directly
uptime_seconds = current_time - connected_at
else:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment