Skip to content

Commit 0a4016d

Browse files
committed
fix: worker cache
1 parent ab59956 commit 0a4016d

File tree

4 files changed

+37
-11
lines changed

4 files changed

+37
-11
lines changed

horde/apis/v2/base.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
from horde.patreon import patrons
4343
from horde.r2 import upload_prompt
4444
from horde.suspicions import Suspicions
45-
from horde.utils import hash_api_key, hash_dictionary, is_profane, sanitize_string
45+
from horde.utils import datetime_parser, hash_api_key, hash_dictionary, is_profane, sanitize_string
4646
from horde.vars import horde_contact_email, horde_title, horde_url
4747

4848
# Not used yet
@@ -873,7 +873,7 @@ def retrieve_workers_details(self):
873873
else:
874874
hr.horde_local_setex_to_json("worker_cache", 300, workers)
875875
return workers
876-
return self.parse_worker_by_query(json.loads(cached_workers))
876+
return self.parse_worker_by_query(json.loads(cached_workers, object_hook=datetime_parser))
877877

878878
def get_worker_info_list(self, details_privilege):
879879
workers_ret = []

horde/classes/stable/waiting_prompt.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
# SPDX-License-Identifier: AGPL-3.0-or-later
44

55
import copy
6+
import math
67
import os
78
import random
8-
import math
99

1010
from sqlalchemy.sql import expression
1111

@@ -415,23 +415,23 @@ def downgrade(self, max_resolution):
415415
area = self.width * self.height
416416
if area > area_limit:
417417
downgraded = True
418-
418+
419419
# Scale to fit into max_resolution
420420
scale = math.sqrt(area_limit / area)
421421
new_width = int(self.width * scale)
422422
new_height = int(self.height * scale)
423-
423+
424424
# Snap down to multiple of 64
425425
new_width = (new_width // 64) * 64
426426
new_height = (new_height // 64) * 64
427-
427+
428428
# Decrement more if needed (just in case we missed some edge case)
429429
while new_width * new_height > area_limit:
430430
if new_width >= new_height:
431431
new_width -= 64
432432
else:
433433
new_height -= 64
434-
434+
435435
# Minimum size
436436
if new_width * new_height < 512 * 512:
437437
new_width = 512
@@ -536,4 +536,3 @@ def get_highest_model_batching_multiplier(self):
536536

537537
def count_pp(self):
538538
return len(self.params.get("post_processing", []))
539-

horde/database/threads.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import json
66
import os
7-
from datetime import datetime, timedelta
7+
from datetime import date, datetime, timedelta
88

99
import patreon
1010
import stripe
@@ -109,6 +109,13 @@ def store_prioritized_wp_queue():
109109
@logger.catch(reraise=True)
110110
def store_worker_list():
111111
"""Stores the retrieved worker details as json for 300 seconds horde-wide"""
112+
113+
def json_serial(obj):
114+
"""JSON serializer for objects not serializable by default json code"""
115+
if isinstance(obj, (datetime, date)):
116+
return obj.isoformat()
117+
raise TypeError(f"Type {type(obj)} not serializable")
118+
112119
with HORDE.app_context():
113120
serialized_workers = []
114121
serialized_workers_privileged = []
@@ -117,8 +124,8 @@ def store_worker_list():
117124
for worker in get_active_workers():
118125
serialized_workers.append(worker.get_details())
119126
serialized_workers_privileged.append(worker.get_details(2))
120-
json_workers = json.dumps(serialized_workers)
121-
json_workers_privileged = json.dumps(serialized_workers_privileged)
127+
json_workers = json.dumps(serialized_workers, default=json_serial)
128+
json_workers_privileged = json.dumps(serialized_workers_privileged, default=json_serial)
122129
try:
123130
hr.horde_r_setex("worker_cache", timedelta(seconds=300), json_workers)
124131
hr.horde_r_setex(

horde/utils.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,23 @@ def ensure_clean(string, key):
155155
if is_profane(string):
156156
raise e.BadRequest(f"{key} contains profanity")
157157
return sanitize_string(string)
158+
159+
160+
# Compiled as a constant to improve performance during high-volume JSON parsing
161+
ISO_DATETIME_RE = re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}")
162+
163+
164+
def datetime_parser(json_dict):
165+
"""
166+
Hook for json.loads to convert ISO 8601 strings back to datetime objects.
167+
Uses a pre-compiled regex for efficiency.
168+
"""
169+
for key, value in json_dict.items():
170+
# Check if it's a string and matches the ISO format pattern
171+
if isinstance(value, str) and ISO_DATETIME_RE.match(value):
172+
try:
173+
json_dict[key] = datetime.fromisoformat(value)
174+
except (ValueError, TypeError):
175+
# Fallback if it looks like a date but doesn't parse correctly
176+
pass
177+
return json_dict

0 commit comments

Comments
 (0)