This commit is contained in:
37
cache/precache.py
vendored
37
cache/precache.py
vendored
@@ -1,7 +1,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from sqlalchemy import and_, join, select
|
from sqlalchemy import and_, func, join, select
|
||||||
|
|
||||||
# Импорт Author, AuthorFollower отложен для избежания циклических импортов
|
# Импорт Author, AuthorFollower отложен для избежания циклических импортов
|
||||||
from cache.cache import cache_author, cache_topic
|
from cache.cache import cache_author, cache_topic
|
||||||
@@ -69,17 +69,30 @@ async def precache_topics_authors(topic_id: int, session) -> None:
|
|||||||
|
|
||||||
# Предварительное кеширование подписчиков тем
|
# Предварительное кеширование подписчиков тем
|
||||||
async def precache_topics_followers(topic_id: int, session) -> None:
|
async def precache_topics_followers(topic_id: int, session) -> None:
|
||||||
|
try:
|
||||||
followers_query = select(TopicFollower.follower).where(TopicFollower.topic == topic_id)
|
followers_query = select(TopicFollower.follower).where(TopicFollower.topic == topic_id)
|
||||||
topic_followers = {row[0] for row in session.execute(followers_query) if row[0]}
|
topic_followers = {row[0] for row in session.execute(followers_query) if row[0]}
|
||||||
|
|
||||||
followers_payload = fast_json_dumps(list(topic_followers))
|
followers_payload = fast_json_dumps(list(topic_followers))
|
||||||
await redis.execute("SET", f"topic:followers:{topic_id}", followers_payload)
|
await redis.execute("SET", f"topic:followers:{topic_id}", followers_payload)
|
||||||
|
|
||||||
|
# Добавляем логирование для отладки
|
||||||
|
logger.debug(f"Precached {len(topic_followers)} followers for topic #{topic_id}")
|
||||||
|
if len(topic_followers) == 0:
|
||||||
|
logger.warning(f"⚠️ Topic #{topic_id} has 0 followers - this might indicate a data issue")
|
||||||
|
elif len(topic_followers) == 1:
|
||||||
|
logger.info(f"ℹ️ Topic #{topic_id} has exactly 1 follower - checking if this is correct")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error precaching followers for topic #{topic_id}: {e}")
|
||||||
|
# В случае ошибки, устанавливаем пустой список
|
||||||
|
await redis.execute("SET", f"topic:followers:{topic_id}", fast_json_dumps([]))
|
||||||
|
|
||||||
|
|
||||||
async def precache_data() -> None:
|
async def precache_data() -> None:
|
||||||
logger.info("precaching...")
|
logger.info("precaching...")
|
||||||
logger.debug("Entering precache_data")
|
logger.debug("Entering precache_data")
|
||||||
try:
|
|
||||||
# Список паттернов ключей, которые нужно сохранить при FLUSHDB
|
# Список паттернов ключей, которые нужно сохранить при FLUSHDB
|
||||||
preserve_patterns = [
|
preserve_patterns = [
|
||||||
"migrated_views_*", # Данные миграции просмотров
|
"migrated_views_*", # Данные миграции просмотров
|
||||||
@@ -92,6 +105,7 @@ async def precache_data() -> None:
|
|||||||
all_keys_to_preserve = []
|
all_keys_to_preserve = []
|
||||||
preserved_data = {}
|
preserved_data = {}
|
||||||
|
|
||||||
|
try:
|
||||||
for pattern in preserve_patterns:
|
for pattern in preserve_patterns:
|
||||||
keys = await redis.execute("KEYS", pattern)
|
keys = await redis.execute("KEYS", pattern)
|
||||||
if keys:
|
if keys:
|
||||||
@@ -153,6 +167,25 @@ async def precache_data() -> None:
|
|||||||
|
|
||||||
logger.info("Beginning topic precache phase")
|
logger.info("Beginning topic precache phase")
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
|
# Проверяем состояние таблицы topic_followers перед кешированием
|
||||||
|
total_followers = session.execute(select(func.count(TopicFollower.topic))).scalar()
|
||||||
|
unique_topics_with_followers = session.execute(
|
||||||
|
select(func.count(func.distinct(TopicFollower.topic)))
|
||||||
|
).scalar()
|
||||||
|
unique_followers = session.execute(select(func.count(func.distinct(TopicFollower.follower)))).scalar()
|
||||||
|
|
||||||
|
logger.info("📊 Database state before precaching:")
|
||||||
|
logger.info(f" Total topic_followers records: {total_followers}")
|
||||||
|
logger.info(f" Unique topics with followers: {unique_topics_with_followers}")
|
||||||
|
logger.info(f" Unique followers: {unique_followers}")
|
||||||
|
|
||||||
|
if total_followers == 0:
|
||||||
|
logger.warning(
|
||||||
|
"🚨 WARNING: topic_followers table is empty! This will cause all topics to show 0 followers."
|
||||||
|
)
|
||||||
|
elif unique_topics_with_followers == 0:
|
||||||
|
logger.warning("🚨 WARNING: No topics have followers! This will cause all topics to show 0 followers.")
|
||||||
|
|
||||||
# topics
|
# topics
|
||||||
q = select(Topic).where(Topic.community == 1)
|
q = select(Topic).where(Topic.community == 1)
|
||||||
topics = get_with_stat(q)
|
topics = get_with_stat(q)
|
||||||
|
|||||||
@@ -1,117 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
Отладочный скрипт для проверки проблемы с количеством подписчиков топиков.
|
|
||||||
|
|
||||||
Проблема: все топики возвращают followers: 1
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
|
||||||
|
|
||||||
from storage.db import local_session
|
|
||||||
from orm.topic import Topic, TopicFollower
|
|
||||||
from orm.author import Author
|
|
||||||
from sqlalchemy import text, func
|
|
||||||
|
|
||||||
def debug_topic_followers():
|
|
||||||
"""Отладка проблемы с подписчиками топиков"""
|
|
||||||
print("🔍 Отладка проблемы с подписчиками топиков")
|
|
||||||
print("=" * 50)
|
|
||||||
|
|
||||||
with local_session() as session:
|
|
||||||
# 1. Проверяем общее количество топиков
|
|
||||||
total_topics = session.query(func.count(Topic.id)).scalar()
|
|
||||||
print(f"📊 Всего топиков в БД: {total_topics}")
|
|
||||||
|
|
||||||
# 2. Проверяем общее количество записей в topic_followers
|
|
||||||
total_followers = session.query(func.count(TopicFollower.topic)).scalar()
|
|
||||||
print(f"👥 Всего записей в topic_followers: {total_followers}")
|
|
||||||
|
|
||||||
# 3. Проверяем уникальные топики с подписчиками
|
|
||||||
topics_with_followers = session.query(func.count(func.distinct(TopicFollower.topic))).scalar()
|
|
||||||
print(f"🎯 Уникальных топиков с подписчиками: {topics_with_followers}")
|
|
||||||
|
|
||||||
# 4. Проверяем уникальных подписчиков
|
|
||||||
unique_followers = session.query(func.count(func.distinct(TopicFollower.follower))).scalar()
|
|
||||||
print(f"👤 Уникальных подписчиков: {unique_followers}")
|
|
||||||
|
|
||||||
# 5. Проверяем распределение подписчиков по топикам
|
|
||||||
print("\n📈 Распределение подписчиков по топикам:")
|
|
||||||
followers_distribution = session.execute(text("""
|
|
||||||
SELECT topic, COUNT(DISTINCT follower) as followers_count
|
|
||||||
FROM topic_followers
|
|
||||||
GROUP BY topic
|
|
||||||
ORDER BY followers_count DESC
|
|
||||||
LIMIT 10
|
|
||||||
""")).fetchall()
|
|
||||||
|
|
||||||
for topic_id, count in followers_distribution:
|
|
||||||
topic_title = session.query(Topic.title).where(Topic.id == topic_id).scalar()
|
|
||||||
print(f" Топик {topic_id} ({topic_title}): {count} подписчиков")
|
|
||||||
|
|
||||||
# 6. Проверяем конкретные топики из вашего примера
|
|
||||||
print("\n🎯 Проверка конкретных топиков:")
|
|
||||||
test_topic_ids = [715, 82, 166] # ID из вашего примера
|
|
||||||
|
|
||||||
for topic_id in test_topic_ids:
|
|
||||||
topic = session.query(Topic).where(Topic.id == topic_id).first()
|
|
||||||
if topic:
|
|
||||||
followers_count = session.query(func.count(TopicFollower.follower)).where(
|
|
||||||
TopicFollower.topic == topic_id
|
|
||||||
).scalar()
|
|
||||||
|
|
||||||
print(f" Топик {topic_id} ({topic.title}): {followers_count} подписчиков")
|
|
||||||
|
|
||||||
# Показываем детали подписчиков
|
|
||||||
if followers_count > 0:
|
|
||||||
followers = session.query(TopicFollower.follower).where(
|
|
||||||
TopicFollower.topic == topic_id
|
|
||||||
).all()
|
|
||||||
follower_ids = [f[0] for f in followers]
|
|
||||||
print(f" Подписчики: {follower_ids}")
|
|
||||||
else:
|
|
||||||
print(f" ❌ Топик {topic_id} не найден")
|
|
||||||
|
|
||||||
# 7. Проверяем SQL запрос, который используется в get_topics_with_stats
|
|
||||||
print("\n🔍 Проверка SQL запроса из get_topics_with_stats:")
|
|
||||||
test_topic_ids_str = ",".join(map(str, test_topic_ids))
|
|
||||||
|
|
||||||
followers_stats_query = f"""
|
|
||||||
SELECT topic, COUNT(DISTINCT follower) as followers_count
|
|
||||||
FROM topic_followers tf
|
|
||||||
WHERE topic IN ({test_topic_ids_str})
|
|
||||||
GROUP BY topic
|
|
||||||
"""
|
|
||||||
|
|
||||||
print(f"SQL: {followers_stats_query}")
|
|
||||||
|
|
||||||
try:
|
|
||||||
result = session.execute(text(followers_stats_query)).fetchall()
|
|
||||||
print("Результат:")
|
|
||||||
for topic_id, count in result:
|
|
||||||
print(f" Топик {topic_id}: {count} подписчиков")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"❌ Ошибка выполнения SQL: {e}")
|
|
||||||
|
|
||||||
# 8. Проверяем, есть ли проблемы с JOIN
|
|
||||||
print("\n🔗 Проверка JOIN с таблицей author:")
|
|
||||||
try:
|
|
||||||
join_query = f"""
|
|
||||||
SELECT tf.topic, tf.follower, a.name as author_name
|
|
||||||
FROM topic_followers tf
|
|
||||||
JOIN author a ON tf.follower = a.id
|
|
||||||
WHERE tf.topic IN ({test_topic_ids_str})
|
|
||||||
ORDER BY tf.topic, tf.follower
|
|
||||||
"""
|
|
||||||
|
|
||||||
join_result = session.execute(text(join_query)).fetchall()
|
|
||||||
print("Результат JOIN:")
|
|
||||||
for topic_id, follower_id, author_name in join_result:
|
|
||||||
print(f" Топик {topic_id} -> Подписчик {follower_id} ({author_name})")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"❌ Ошибка JOIN: {e}")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
debug_topic_followers()
|
|
||||||
Reference in New Issue
Block a user