添加不使用Redis配置
This commit is contained in:
parent
f3ede6cb19
commit
8ad03fcbf2
26
QUICK_FIX.bat
Normal file
26
QUICK_FIX.bat
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
@echo off
|
||||||
|
echo ============================================================
|
||||||
|
echo Fixing Redis Cache UTF-8 Decode Error
|
||||||
|
echo ============================================================
|
||||||
|
echo.
|
||||||
|
|
||||||
|
echo Step 1: Flushing Redis database 1...
|
||||||
|
redis-cli -n 1 FLUSHDB
|
||||||
|
echo Done!
|
||||||
|
echo.
|
||||||
|
|
||||||
|
echo Step 2: Clearing Django cache...
|
||||||
|
python manage.py clear_cache
|
||||||
|
echo Done!
|
||||||
|
echo.
|
||||||
|
|
||||||
|
echo Step 3: Reinitializing system config...
|
||||||
|
python fix_cache.py
|
||||||
|
echo Done!
|
||||||
|
echo.
|
||||||
|
|
||||||
|
echo ============================================================
|
||||||
|
echo Cache fixed! Now restart your Django server:
|
||||||
|
echo python manage.py runserver
|
||||||
|
echo ============================================================
|
||||||
|
pause
|
||||||
Binary file not shown.
@ -5,7 +5,41 @@ from django.db import connection
|
|||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from dvadmin.utils.validator import CustomValidationError
|
from dvadmin.utils.validator import CustomValidationError
|
||||||
|
|
||||||
dispatch_db_type = getattr(settings, 'DISPATCH_DB_TYPE', 'redis') # redis
|
# 检查是否使用Redis
|
||||||
|
try:
|
||||||
|
from conf.env import USE_REDIS
|
||||||
|
except ImportError:
|
||||||
|
USE_REDIS = getattr(settings, 'USE_REDIS', False)
|
||||||
|
|
||||||
|
dispatch_db_type = getattr(settings, 'DISPATCH_DB_TYPE', 'redis' if USE_REDIS else 'database') # 根据USE_REDIS自动选择
|
||||||
|
|
||||||
|
|
||||||
|
def _delete_corrupted_cache_key(key):
|
||||||
|
"""
|
||||||
|
Delete a corrupted cache key using raw Redis client to bypass Django cache decode
|
||||||
|
"""
|
||||||
|
if not USE_REDIS:
|
||||||
|
# 如果不是使用Redis,直接使用cache.delete
|
||||||
|
cache.delete(key)
|
||||||
|
return True
|
||||||
|
|
||||||
|
try:
|
||||||
|
import redis
|
||||||
|
from conf.env import REDIS_HOST, REDIS_PASSWORD, REDIS_DB
|
||||||
|
if REDIS_PASSWORD:
|
||||||
|
r = redis.Redis(host=REDIS_HOST, port=6379, db=REDIS_DB, password=REDIS_PASSWORD)
|
||||||
|
else:
|
||||||
|
r = redis.Redis(host=REDIS_HOST, port=6379, db=REDIS_DB)
|
||||||
|
|
||||||
|
# Use raw Redis delete to bypass Django's cache layer
|
||||||
|
# Django adds a prefix, try both with and without
|
||||||
|
deleted = r.delete(key)
|
||||||
|
deleted += r.delete(f":1:{key}") # Django cache with version prefix
|
||||||
|
print(f"Deleted {deleted} corrupted cache key(s) for: {key}")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error deleting corrupted key {key}: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def is_tenants_mode():
|
def is_tenants_mode():
|
||||||
@ -157,10 +191,20 @@ def get_dictionary_config(schema_name=None):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
if dispatch_db_type == 'redis':
|
if dispatch_db_type == 'redis':
|
||||||
|
try:
|
||||||
init_dictionary_data = cache.get(f"init_dictionary")
|
init_dictionary_data = cache.get(f"init_dictionary")
|
||||||
if not init_dictionary_data:
|
if not init_dictionary_data:
|
||||||
refresh_dictionary()
|
refresh_dictionary()
|
||||||
return cache.get(f"init_dictionary") or {}
|
return cache.get(f"init_dictionary") or {}
|
||||||
|
except (UnicodeDecodeError, Exception) as e:
|
||||||
|
# Handle corrupted cache data - delete using raw Redis and refresh
|
||||||
|
print(f"Cache decode error, clearing corrupted key: {e}")
|
||||||
|
_delete_corrupted_cache_key("init_dictionary")
|
||||||
|
refresh_dictionary()
|
||||||
|
try:
|
||||||
|
return cache.get(f"init_dictionary") or {}
|
||||||
|
except:
|
||||||
|
return {}
|
||||||
if not settings.DICTIONARY_CONFIG:
|
if not settings.DICTIONARY_CONFIG:
|
||||||
refresh_dictionary()
|
refresh_dictionary()
|
||||||
if is_tenants_mode():
|
if is_tenants_mode():
|
||||||
@ -178,11 +222,22 @@ def get_dictionary_values(key, schema_name=None):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
if dispatch_db_type == 'redis':
|
if dispatch_db_type == 'redis':
|
||||||
|
try:
|
||||||
dictionary_config = cache.get(f"init_dictionary")
|
dictionary_config = cache.get(f"init_dictionary")
|
||||||
if not dictionary_config:
|
if not dictionary_config:
|
||||||
refresh_dictionary()
|
refresh_dictionary()
|
||||||
dictionary_config = cache.get(f"init_dictionary")
|
dictionary_config = cache.get(f"init_dictionary")
|
||||||
return dictionary_config.get(key)
|
return dictionary_config.get(key)
|
||||||
|
except (UnicodeDecodeError, Exception) as e:
|
||||||
|
# Handle corrupted cache data - delete using raw Redis and refresh
|
||||||
|
print(f"Cache decode error, clearing corrupted key: {e}")
|
||||||
|
_delete_corrupted_cache_key("init_dictionary")
|
||||||
|
refresh_dictionary()
|
||||||
|
try:
|
||||||
|
dictionary_config = cache.get(f"init_dictionary")
|
||||||
|
return dictionary_config.get(key) if dictionary_config else None
|
||||||
|
except:
|
||||||
|
return None
|
||||||
dictionary_config = get_dictionary_config(schema_name)
|
dictionary_config = get_dictionary_config(schema_name)
|
||||||
return dictionary_config.get(key)
|
return dictionary_config.get(key)
|
||||||
|
|
||||||
@ -214,10 +269,20 @@ def get_system_config(schema_name=None):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
if dispatch_db_type == 'redis':
|
if dispatch_db_type == 'redis':
|
||||||
|
try:
|
||||||
init_dictionary_data = cache.get(f"init_system_config")
|
init_dictionary_data = cache.get(f"init_system_config")
|
||||||
if not init_dictionary_data:
|
if not init_dictionary_data:
|
||||||
refresh_system_config()
|
refresh_system_config()
|
||||||
return cache.get(f"init_system_config") or {}
|
return cache.get(f"init_system_config") or {}
|
||||||
|
except (UnicodeDecodeError, Exception) as e:
|
||||||
|
# Handle corrupted cache data - delete using raw Redis and refresh
|
||||||
|
print(f"Cache decode error, clearing corrupted key: {e}")
|
||||||
|
_delete_corrupted_cache_key("init_system_config")
|
||||||
|
refresh_system_config()
|
||||||
|
try:
|
||||||
|
return cache.get(f"init_system_config") or {}
|
||||||
|
except:
|
||||||
|
return {}
|
||||||
if not settings.SYSTEM_CONFIG:
|
if not settings.SYSTEM_CONFIG:
|
||||||
refresh_system_config()
|
refresh_system_config()
|
||||||
if is_tenants_mode():
|
if is_tenants_mode():
|
||||||
@ -235,11 +300,22 @@ def get_system_config_values(key, schema_name=None):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
if dispatch_db_type == 'redis':
|
if dispatch_db_type == 'redis':
|
||||||
|
try:
|
||||||
system_config = cache.get(f"init_system_config")
|
system_config = cache.get(f"init_system_config")
|
||||||
if not system_config:
|
if not system_config:
|
||||||
refresh_system_config()
|
refresh_system_config()
|
||||||
system_config = cache.get(f"init_system_config")
|
system_config = cache.get(f"init_system_config")
|
||||||
return system_config.get(key)
|
return system_config.get(key)
|
||||||
|
except (UnicodeDecodeError, Exception) as e:
|
||||||
|
# Handle corrupted cache data - delete using raw Redis and refresh
|
||||||
|
print(f"Cache decode error, clearing corrupted key: {e}")
|
||||||
|
_delete_corrupted_cache_key("init_system_config")
|
||||||
|
refresh_system_config()
|
||||||
|
try:
|
||||||
|
system_config = cache.get(f"init_system_config")
|
||||||
|
return system_config.get(key) if system_config else None
|
||||||
|
except:
|
||||||
|
return None
|
||||||
system_config = get_system_config(schema_name)
|
system_config = get_system_config(schema_name)
|
||||||
return system_config.get(key)
|
return system_config.get(key)
|
||||||
|
|
||||||
|
|||||||
@ -175,13 +175,17 @@ STATICFILES_FINDERS = (
|
|||||||
# ================================================= #
|
# ================================================= #
|
||||||
# ******************* Redis缓存配置 ******************* #
|
# ******************* Redis缓存配置 ******************* #
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
# 根据是否有密码决定Redis URL格式
|
# 是否使用Redis,如果不使用Redis则使用本地内存缓存
|
||||||
if REDIS_PASSWORD:
|
USE_REDIS = getattr(locals(), "USE_REDIS", False)
|
||||||
|
|
||||||
|
if USE_REDIS:
|
||||||
|
# 使用Redis缓存
|
||||||
|
if REDIS_PASSWORD:
|
||||||
REDIS_CACHE_URL = f"redis://:{REDIS_PASSWORD}@{REDIS_HOST}:6379/{REDIS_DB}"
|
REDIS_CACHE_URL = f"redis://:{REDIS_PASSWORD}@{REDIS_HOST}:6379/{REDIS_DB}"
|
||||||
else:
|
else:
|
||||||
REDIS_CACHE_URL = f"redis://{REDIS_HOST}:6379/{REDIS_DB}"
|
REDIS_CACHE_URL = f"redis://{REDIS_HOST}:6379/{REDIS_DB}"
|
||||||
|
|
||||||
CACHES = {
|
CACHES = {
|
||||||
"default": {
|
"default": {
|
||||||
"BACKEND": "django_redis.cache.RedisCache",
|
"BACKEND": "django_redis.cache.RedisCache",
|
||||||
"LOCATION": REDIS_CACHE_URL,
|
"LOCATION": REDIS_CACHE_URL,
|
||||||
@ -195,7 +199,15 @@ CACHES = {
|
|||||||
"SOCKET_TIMEOUT": 5, # 读写超时时间(秒)
|
"SOCKET_TIMEOUT": 5, # 读写超时时间(秒)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else:
|
||||||
|
# 使用本地内存缓存(不使用Redis)
|
||||||
|
CACHES = {
|
||||||
|
"default": {
|
||||||
|
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
|
||||||
|
"LOCATION": "unique-snowflake",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
# ******************* 跨域的配置 ******************* #
|
# ******************* 跨域的配置 ******************* #
|
||||||
@ -214,12 +226,10 @@ CORS_ALLOW_CREDENTIALS = True # 指明在跨域访问中,后端是否支持
|
|||||||
# ********************* channels配置 ******************* #
|
# ********************* channels配置 ******************* #
|
||||||
# ===================================================== #
|
# ===================================================== #
|
||||||
ASGI_APPLICATION = 'application.asgi.application'
|
ASGI_APPLICATION = 'application.asgi.application'
|
||||||
# CHANNEL_LAYERS = {
|
|
||||||
# "default": {
|
# 根据是否使用Redis选择channel layer
|
||||||
# "BACKEND": "channels.layers.InMemoryChannelLayer"
|
if USE_REDIS:
|
||||||
# }
|
CHANNEL_LAYERS = {
|
||||||
# }
|
|
||||||
CHANNEL_LAYERS = {
|
|
||||||
'default': {
|
'default': {
|
||||||
'BACKEND': 'channels_redis.core.RedisChannelLayer',
|
'BACKEND': 'channels_redis.core.RedisChannelLayer',
|
||||||
'CONFIG': {
|
'CONFIG': {
|
||||||
@ -228,7 +238,14 @@ CHANNEL_LAYERS = {
|
|||||||
"db": REDIS_DB,
|
"db": REDIS_DB,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
else:
|
||||||
|
# 不使用Redis,使用内存channel layer
|
||||||
|
CHANNEL_LAYERS = {
|
||||||
|
"default": {
|
||||||
|
"BACKEND": "channels.layers.InMemoryChannelLayer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
@ -418,13 +435,23 @@ API_MODEL_MAP = {
|
|||||||
|
|
||||||
DJANGO_CELERY_BEAT_TZ_AWARE = False
|
DJANGO_CELERY_BEAT_TZ_AWARE = False
|
||||||
CELERY_TIMEZONE = "Asia/Shanghai" # celery 时区问题
|
CELERY_TIMEZONE = "Asia/Shanghai" # celery 时区问题
|
||||||
# Celery配置 - 使用Redis作为broker和result backend
|
# Celery配置 - 根据是否使用Redis选择broker和result backend
|
||||||
if REDIS_PASSWORD:
|
if USE_REDIS:
|
||||||
|
# 使用Redis作为broker和result backend
|
||||||
|
if REDIS_PASSWORD:
|
||||||
CELERY_BROKER_URL = f"redis://:{REDIS_PASSWORD}@{REDIS_HOST}:6379/{CELERY_BROKER_DB}"
|
CELERY_BROKER_URL = f"redis://:{REDIS_PASSWORD}@{REDIS_HOST}:6379/{CELERY_BROKER_DB}"
|
||||||
CELERY_RESULT_BACKEND = f"redis://:{REDIS_PASSWORD}@{REDIS_HOST}:6379/{REDIS_DB}"
|
CELERY_RESULT_BACKEND = f"redis://:{REDIS_PASSWORD}@{REDIS_HOST}:6379/{REDIS_DB}"
|
||||||
else:
|
else:
|
||||||
CELERY_BROKER_URL = f"redis://{REDIS_HOST}:6379/{CELERY_BROKER_DB}"
|
CELERY_BROKER_URL = f"redis://{REDIS_HOST}:6379/{CELERY_BROKER_DB}"
|
||||||
CELERY_RESULT_BACKEND = f"redis://{REDIS_HOST}:6379/{REDIS_DB}"
|
CELERY_RESULT_BACKEND = f"redis://{REDIS_HOST}:6379/{REDIS_DB}"
|
||||||
|
else:
|
||||||
|
# 不使用Redis,使用Dummy broker(Celery将不会真正运行任务)
|
||||||
|
# 如果需要真正的异步任务,请安装并配置RabbitMQ,或使用数据库作为broker
|
||||||
|
CELERY_BROKER_URL = "amqp://guest@localhost//" # 需要RabbitMQ,如果没有则使用dummy
|
||||||
|
CELERY_RESULT_BACKEND = "cache+memory://" # 使用内存存储结果
|
||||||
|
# 注意:如果没有RabbitMQ,Celery任务将不会真正执行
|
||||||
|
# 可以使用数据库作为broker:CELERY_BROKER_URL = "db+sqlite:///celery_broker.sqlite"
|
||||||
|
# 但这需要安装kombu[db]或kombu[sqlalchemy]
|
||||||
CELERY_ACCEPT_CONTENT = ['json']
|
CELERY_ACCEPT_CONTENT = ['json']
|
||||||
CELERY_TASK_SERIALIZER = 'json'
|
CELERY_TASK_SERIALIZER = 'json'
|
||||||
CELERY_RESULT_SERIALIZER = 'json'
|
CELERY_RESULT_SERIALIZER = 'json'
|
||||||
|
|||||||
67
check_db.py
Normal file
67
check_db.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Check database for SystemConfig issues
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import django
|
||||||
|
|
||||||
|
# Setup Django environment
|
||||||
|
sys.path.insert(0, os.path.dirname(__file__))
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
|
||||||
|
django.setup()
|
||||||
|
|
||||||
|
from dvadmin.system.models import SystemConfig
|
||||||
|
|
||||||
|
print("=" * 60)
|
||||||
|
print("Checking SystemConfig Database")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Check if table exists and has data
|
||||||
|
count = SystemConfig.objects.count()
|
||||||
|
print(f"\n✓ SystemConfig table exists")
|
||||||
|
print(f"✓ Found {count} records")
|
||||||
|
|
||||||
|
if count == 0:
|
||||||
|
print("\n⚠ WARNING: No system config records found!")
|
||||||
|
print(" You may need to run: python manage.py init")
|
||||||
|
else:
|
||||||
|
# Check for problematic records
|
||||||
|
print("\nChecking for problematic records...")
|
||||||
|
configs = SystemConfig.objects.filter(parent_id__isnull=False).values(
|
||||||
|
'id', 'parent__key', 'key', 'value', 'form_item_type'
|
||||||
|
)[:10]
|
||||||
|
|
||||||
|
print(f"\nFirst 10 config records:")
|
||||||
|
for config in configs:
|
||||||
|
key_name = f"{config.get('parent__key')}.{config.get('key')}"
|
||||||
|
value = config.get('value')
|
||||||
|
print(f" - {key_name}: {type(value).__name__} = {str(value)[:50]}...")
|
||||||
|
|
||||||
|
# Try to build the config dict like dispatch does
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("Testing config building (like dispatch.py does)...")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
from application.dispatch import _get_all_system_config
|
||||||
|
try:
|
||||||
|
data = _get_all_system_config()
|
||||||
|
print(f"\n✓ Successfully built config dict with {len(data)} keys")
|
||||||
|
print("\nSample keys:")
|
||||||
|
for i, (k, v) in enumerate(list(data.items())[:5]):
|
||||||
|
print(f" - {k}: {type(v).__name__}")
|
||||||
|
if i >= 4:
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\n✗ ERROR building config: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\n✗ ERROR: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
print("\n" + "=" * 60)
|
||||||
@ -28,6 +28,10 @@ TABLE_PREFIX = "dvadmin_"
|
|||||||
# ================================================= #
|
# ================================================= #
|
||||||
# ******** redis配置,无redis 可不进行配置 ******** #
|
# ******** redis配置,无redis 可不进行配置 ******** #
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
|
# 是否使用Redis,设置为False则不使用Redis(使用本地内存缓存和数据库)
|
||||||
|
USE_REDIS = False
|
||||||
|
|
||||||
|
# 以下Redis配置仅在USE_REDIS=True时生效
|
||||||
REDIS_DB = 1
|
REDIS_DB = 1
|
||||||
CELERY_BROKER_DB = 3
|
CELERY_BROKER_DB = 3
|
||||||
REDIS_PASSWORD = 'DVADMIN3'
|
REDIS_PASSWORD = 'DVADMIN3'
|
||||||
|
|||||||
@ -28,6 +28,10 @@ TABLE_PREFIX = "dvadmin_"
|
|||||||
# ================================================= #
|
# ================================================= #
|
||||||
# ******** redis配置,无redis 可不进行配置 ******** #
|
# ******** redis配置,无redis 可不进行配置 ******** #
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
|
# 是否使用Redis,设置为False则不使用Redis(使用本地内存缓存和数据库)
|
||||||
|
USE_REDIS = False
|
||||||
|
|
||||||
|
# 以下Redis配置仅在USE_REDIS=True时生效
|
||||||
REDIS_DB = 1
|
REDIS_DB = 1
|
||||||
CELERY_BROKER_DB = 3
|
CELERY_BROKER_DB = 3
|
||||||
REDIS_PASSWORD = '' # 无密码的Redis服务器
|
REDIS_PASSWORD = '' # 无密码的Redis服务器
|
||||||
|
|||||||
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
17
dvadmin/system/management/commands/clear_cache.py
Normal file
17
dvadmin/system/management/commands/clear_cache.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Clear Django cache to fix UTF-8 decode errors
|
||||||
|
"""
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.core.cache import cache
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Clear Django cache (useful for fixing UTF-8 decode errors)'
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
try:
|
||||||
|
cache.clear()
|
||||||
|
self.stdout.write(self.style.SUCCESS('Successfully cleared cache!'))
|
||||||
|
except Exception as e:
|
||||||
|
self.stdout.write(self.style.ERROR(f'Failed to clear cache: {e}'))
|
||||||
112
fix_cache.py
Normal file
112
fix_cache.py
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Fix corrupted Redis cache by deleting specific keys
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import django
|
||||||
|
|
||||||
|
# Setup Django environment
|
||||||
|
sys.path.insert(0, os.path.dirname(__file__))
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
|
||||||
|
django.setup()
|
||||||
|
|
||||||
|
import redis
|
||||||
|
from conf.env import REDIS_HOST, REDIS_PASSWORD, REDIS_DB
|
||||||
|
|
||||||
|
def fix_cache():
|
||||||
|
"""Delete corrupted cache keys"""
|
||||||
|
try:
|
||||||
|
# Create Redis connection
|
||||||
|
if REDIS_PASSWORD:
|
||||||
|
r = redis.Redis(host=REDIS_HOST, port=6379, db=REDIS_DB, password=REDIS_PASSWORD)
|
||||||
|
else:
|
||||||
|
r = redis.Redis(host=REDIS_HOST, port=6379, db=REDIS_DB)
|
||||||
|
|
||||||
|
print("=" * 60)
|
||||||
|
print("Fixing corrupted Redis cache...")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
# List of keys that might be corrupted
|
||||||
|
problem_keys = [
|
||||||
|
'init_system_config',
|
||||||
|
'init_dictionary',
|
||||||
|
':1:init_system_config',
|
||||||
|
':1:init_dictionary',
|
||||||
|
]
|
||||||
|
|
||||||
|
deleted_count = 0
|
||||||
|
for key in problem_keys:
|
||||||
|
try:
|
||||||
|
# Try to get the key
|
||||||
|
exists = r.exists(key)
|
||||||
|
if exists:
|
||||||
|
print(f"\n✓ Found key: {key}")
|
||||||
|
# Try to decode it
|
||||||
|
try:
|
||||||
|
value = r.get(key)
|
||||||
|
if value:
|
||||||
|
# Try to decode as UTF-8
|
||||||
|
value.decode('utf-8')
|
||||||
|
print(f" → Key is OK (can be decoded)")
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
print(f" → Key is CORRUPTED (UTF-8 decode error)")
|
||||||
|
r.delete(key)
|
||||||
|
print(f" → DELETED corrupted key")
|
||||||
|
deleted_count += 1
|
||||||
|
except Exception as e:
|
||||||
|
print(f" → Error checking key: {e}")
|
||||||
|
r.delete(key)
|
||||||
|
print(f" → DELETED problematic key")
|
||||||
|
deleted_count += 1
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Error processing key {key}: {e}")
|
||||||
|
|
||||||
|
# Also clear all keys with pattern
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("Searching for all cache keys...")
|
||||||
|
all_keys = r.keys('*')
|
||||||
|
print(f"Found {len(all_keys)} total keys in Redis DB {REDIS_DB}")
|
||||||
|
|
||||||
|
if all_keys:
|
||||||
|
print("\nChecking all keys for corruption...")
|
||||||
|
for key in all_keys:
|
||||||
|
try:
|
||||||
|
key_str = key.decode('utf-8') if isinstance(key, bytes) else key
|
||||||
|
value = r.get(key)
|
||||||
|
if value:
|
||||||
|
try:
|
||||||
|
value.decode('utf-8')
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
print(f" → Corrupted key found: {key_str}")
|
||||||
|
r.delete(key)
|
||||||
|
deleted_count += 1
|
||||||
|
print(f" → DELETED")
|
||||||
|
except Exception as e:
|
||||||
|
print(f" → Error with key: {e}")
|
||||||
|
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print(f"✓ Fixed! Deleted {deleted_count} corrupted keys")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
# Now reinitialize the cache
|
||||||
|
print("\nReinitializing system config...")
|
||||||
|
from application import dispatch
|
||||||
|
dispatch.refresh_system_config()
|
||||||
|
dispatch.refresh_dictionary()
|
||||||
|
print("✓ System config reinitialized!")
|
||||||
|
|
||||||
|
return True
|
||||||
|
except redis.ConnectionError as e:
|
||||||
|
print(f"✗ Redis connection failed: {e}")
|
||||||
|
print(" Make sure Redis server is running")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Error: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return False
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
fix_cache()
|
||||||
4596
logs/error.log
4596
logs/error.log
File diff suppressed because it is too large
Load Diff
4963
logs/server.log
4963
logs/server.log
File diff suppressed because it is too large
Load Diff
79
test_redis.py
Normal file
79
test_redis.py
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Test Redis connection and clear cache if needed
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import django
|
||||||
|
|
||||||
|
# Setup Django environment
|
||||||
|
sys.path.insert(0, os.path.dirname(__file__))
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
|
||||||
|
django.setup()
|
||||||
|
|
||||||
|
from django.core.cache import cache
|
||||||
|
import redis
|
||||||
|
|
||||||
|
def test_redis_connection():
|
||||||
|
"""Test if Redis is accessible"""
|
||||||
|
try:
|
||||||
|
from conf.env import REDIS_HOST, REDIS_PASSWORD, REDIS_DB
|
||||||
|
|
||||||
|
# Create Redis connection
|
||||||
|
if REDIS_PASSWORD:
|
||||||
|
r = redis.Redis(host=REDIS_HOST, port=6379, db=REDIS_DB, password=REDIS_PASSWORD, decode_responses=True)
|
||||||
|
else:
|
||||||
|
r = redis.Redis(host=REDIS_HOST, port=6379, db=REDIS_DB, decode_responses=True)
|
||||||
|
|
||||||
|
# Test connection
|
||||||
|
response = r.ping()
|
||||||
|
print(f"✓ Redis connection successful: {response}")
|
||||||
|
|
||||||
|
# Get all keys
|
||||||
|
keys = r.keys('*')
|
||||||
|
print(f"✓ Found {len(keys)} keys in Redis database {REDIS_DB}")
|
||||||
|
|
||||||
|
if keys:
|
||||||
|
print("\nKeys in Redis:")
|
||||||
|
for key in keys[:10]: # Show first 10 keys
|
||||||
|
print(f" - {key}")
|
||||||
|
if len(keys) > 10:
|
||||||
|
print(f" ... and {len(keys) - 10} more")
|
||||||
|
|
||||||
|
return True
|
||||||
|
except redis.ConnectionError as e:
|
||||||
|
print(f"✗ Redis connection failed: {e}")
|
||||||
|
print(" Make sure Redis server is running: redis-server")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Error: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def clear_django_cache():
|
||||||
|
"""Clear Django cache"""
|
||||||
|
try:
|
||||||
|
cache.clear()
|
||||||
|
print("\n✓ Django cache cleared successfully!")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\n✗ Failed to clear Django cache: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print("=" * 60)
|
||||||
|
print("Redis Connection Test & Cache Clear Utility")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
if test_redis_connection():
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
choice = input("\nDo you want to clear the Django cache? (y/n): ").lower()
|
||||||
|
if choice == 'y':
|
||||||
|
clear_django_cache()
|
||||||
|
else:
|
||||||
|
print("Cache not cleared.")
|
||||||
|
else:
|
||||||
|
print("\n⚠ Cannot clear cache - Redis connection failed")
|
||||||
|
print("Please start Redis server first: redis-server")
|
||||||
|
|
||||||
|
print("\n" + "=" * 60)
|
||||||
150
不使用Redis配置说明.md
Normal file
150
不使用Redis配置说明.md
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
# 不使用Redis的配置说明
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
本项目支持两种运行模式:
|
||||||
|
1. **使用Redis模式** - 生产环境推荐,提供分布式缓存和更好的性能
|
||||||
|
2. **不使用Redis模式** - 开发/测试环境推荐,使用本地内存缓存,无需安装Redis
|
||||||
|
|
||||||
|
## 配置方式
|
||||||
|
|
||||||
|
### 不使用Redis配置
|
||||||
|
|
||||||
|
在 `conf/env.py` 文件中,将 `USE_REDIS` 设置为 `False`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# ================================================= #
|
||||||
|
# ******** redis配置,无redis 可不进行配置 ******** #
|
||||||
|
# ================================================= #
|
||||||
|
# 是否使用Redis,设置为False则不使用Redis(使用本地内存缓存和数据库)
|
||||||
|
USE_REDIS = False # 设置为False
|
||||||
|
|
||||||
|
# 以下Redis配置仅在USE_REDIS=True时生效
|
||||||
|
REDIS_DB = 1
|
||||||
|
CELERY_BROKER_DB = 3
|
||||||
|
REDIS_PASSWORD = ''
|
||||||
|
REDIS_HOST = '127.0.0.1'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 使用Redis配置
|
||||||
|
|
||||||
|
如果需要使用Redis,将 `USE_REDIS` 设置为 `True`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
USE_REDIS = True # 设置为True
|
||||||
|
|
||||||
|
# 配置Redis连接信息
|
||||||
|
REDIS_DB = 1
|
||||||
|
CELERY_BROKER_DB = 3
|
||||||
|
REDIS_PASSWORD = 'your_password' # Redis密码,无密码则留空
|
||||||
|
REDIS_HOST = '127.0.0.1' # Redis服务器地址
|
||||||
|
```
|
||||||
|
|
||||||
|
## 不同配置下的行为
|
||||||
|
|
||||||
|
### 1. 缓存系统
|
||||||
|
|
||||||
|
| 配置 | 缓存后端 | 说明 |
|
||||||
|
|------|---------|------|
|
||||||
|
| `USE_REDIS = False` | `django.core.cache.backends.locmem.LocMemCache` | 本地内存缓存 |
|
||||||
|
| `USE_REDIS = True` | `django_redis.cache.RedisCache` | Redis分布式缓存 |
|
||||||
|
|
||||||
|
**注意**:本地内存缓存在多进程部署环境下不共享,重启后数据会丢失。
|
||||||
|
|
||||||
|
### 2. Channels(WebSocket/SSE)
|
||||||
|
|
||||||
|
| 配置 | Channel Layer | 说明 |
|
||||||
|
|------|--------------|------|
|
||||||
|
| `USE_REDIS = False` | `channels.layers.InMemoryChannelLayer` | 内存通道层 |
|
||||||
|
| `USE_REDIS = True` | `channels_redis.core.RedisChannelLayer` | Redis通道层 |
|
||||||
|
|
||||||
|
**注意**:内存通道层在多实例部署环境下不支持跨实例通信。
|
||||||
|
|
||||||
|
### 3. Celery异步任务
|
||||||
|
|
||||||
|
| 配置 | Broker | Result Backend | 说明 |
|
||||||
|
|------|--------|---------------|------|
|
||||||
|
| `USE_REDIS = False` | `amqp://guest@localhost//` | `cache+memory://` | 需要RabbitMQ |
|
||||||
|
| `USE_REDIS = True` | `redis://...` | `redis://...` | Redis作为broker和backend |
|
||||||
|
|
||||||
|
**注意**:
|
||||||
|
- 不使用Redis时,Celery需要RabbitMQ作为broker
|
||||||
|
- 如果项目不使用Celery异步任务,可以忽略此配置
|
||||||
|
- 可以使用数据库作为broker(需要额外配置)
|
||||||
|
|
||||||
|
### 4. 系统配置和字典缓存
|
||||||
|
|
||||||
|
| 配置 | 存储方式 | 说明 |
|
||||||
|
|------|---------|------|
|
||||||
|
| `USE_REDIS = False` | 从数据库读取 | 每次查询数据库 |
|
||||||
|
| `USE_REDIS = True` | Redis缓存 | 首次查询后缓存到Redis |
|
||||||
|
|
||||||
|
## 部署建议
|
||||||
|
|
||||||
|
### 开发/测试环境
|
||||||
|
```python
|
||||||
|
USE_REDIS = False # 推荐,简化环境配置
|
||||||
|
```
|
||||||
|
|
||||||
|
### 单机生产环境
|
||||||
|
```python
|
||||||
|
USE_REDIS = False # 可接受,但建议使用Redis以提高性能
|
||||||
|
```
|
||||||
|
|
||||||
|
### 多实例/分布式生产环境
|
||||||
|
```python
|
||||||
|
USE_REDIS = True # 必需,确保多实例间数据共享
|
||||||
|
```
|
||||||
|
|
||||||
|
## 性能对比
|
||||||
|
|
||||||
|
| 场景 | 不使用Redis | 使用Redis |
|
||||||
|
|------|-----------|----------|
|
||||||
|
| 缓存查询速度 | 快(内存) | 快(内存+网络) |
|
||||||
|
| 多实例数据共享 | ❌ 不支持 | ✅ 支持 |
|
||||||
|
| 缓存持久化 | ❌ 不支持 | ✅ 支持(可配置) |
|
||||||
|
| 部署复杂度 | ✅ 简单 | ⚠️ 需要部署Redis |
|
||||||
|
| 成本 | ✅ 免费 | ⚠️ 需要服务器资源 |
|
||||||
|
|
||||||
|
## 切换配置
|
||||||
|
|
||||||
|
1. 修改 `conf/env.py` 中的 `USE_REDIS` 配置
|
||||||
|
2. 重启Django服务
|
||||||
|
3. 如果从Redis切换到非Redis,建议清理之前的Redis缓存
|
||||||
|
|
||||||
|
## 故障排查
|
||||||
|
|
||||||
|
### 问题:项目启动报错,提示Redis连接失败
|
||||||
|
|
||||||
|
**解决方案**:
|
||||||
|
- 检查 `USE_REDIS` 是否正确设置为 `False`
|
||||||
|
- 确认 `conf/env.py` 文件已保存
|
||||||
|
|
||||||
|
### 问题:多用户环境下缓存不同步
|
||||||
|
|
||||||
|
**解决方案**:
|
||||||
|
- 如果在多实例部署环境,必须使用Redis
|
||||||
|
- 将 `USE_REDIS` 设置为 `True` 并配置Redis服务器
|
||||||
|
|
||||||
|
### 问题:Celery任务无法执行
|
||||||
|
|
||||||
|
**解决方案**:
|
||||||
|
- 检查是否安装了RabbitMQ或Redis
|
||||||
|
- 确认Celery worker是否正在运行
|
||||||
|
- 不使用异步任务时,可以忽略Celery相关配置
|
||||||
|
|
||||||
|
## 相关文件
|
||||||
|
|
||||||
|
- `conf/env.py` - 环境配置文件
|
||||||
|
- `conf/env.example.py` - 环境配置示例文件
|
||||||
|
- `application/settings.py` - Django主配置文件
|
||||||
|
- `application/dispatch.py` - 缓存相关工具函数
|
||||||
|
|
||||||
|
## 依赖说明
|
||||||
|
|
||||||
|
不使用Redis时,以下依赖仍然需要安装(用于其他功能):
|
||||||
|
- `django-redis==5.4.0` - Redis支持库(可选依赖)
|
||||||
|
- `channels-redis==4.2.0` - Channels Redis支持(可选依赖)
|
||||||
|
- `redis` - Redis客户端库(可选依赖)
|
||||||
|
|
||||||
|
这些依赖只在 `USE_REDIS = True` 时才会被使用。
|
||||||
Loading…
Reference in New Issue
Block a user