使用Django Redis缓存重启manager.py后对象属性丢失问题排查
1. 类属性与实例属性混淆
你定义的CrossSectionFactory中,cross_section_sequence是类属性,所有该类的实例共享这个字典。调用add方法修改它时,实际修改的是类本身的属性,而非单个实例独有的属性。而Django Redis缓存仅序列化实例对象,类属性不会被存入缓存——缓存只保存实例自身的状态,不关联类的全局状态。
2. 进程重启后的类状态重置
重启manager.py后,新进程会重新加载所有类定义,CrossSectionFactory的cross_section_sequence会被重新初始化为空字典。此时从缓存反序列化出来的Analyzer实例,其cross_section_factory仍引用新进程中的类属性,自然会看到空字典。
3. 旧缓存键的数据干扰
旧缓存键对应的是进程重启前的实例状态,但该实例关联的类属性状态并未被缓存。更换缓存键后,新缓存的是进程重启后创建的实例(此时实例已生成独立的属性状态),因此能正常读写。
1. 将类属性改为实例属性
修改CrossSectionFactory,在__init__方法中初始化cross_section_sequence为实例属性,确保每个实例拥有独立的字典:
class CrossSectionFactory(LoggerMixin): def __init__(self, logger=None, **kwargs): super().__init__(logger=logger, **kwargs) self.cross_section_sequence = {} # 改为实例属性 def add(self, date): cross_section = CrossSection() self.cross_section_sequence[date] = cross_section
这样每个CrossSectionFactory实例的字典都是独立的,序列化时会将该属性一并存入缓存,重启进程后反序列化的实例能保留原有数据。
2. 清理旧缓存
删除之前的旧缓存键,避免反序列化出关联旧类状态的实例:
cache.delete("analyzer:1")
3. 验证序列化兼容性
确保自定义类(CrossSection、CrossSectionFactory、Analyzer)支持pickle序列化(Django Redis缓存默认用pickle)。如果LoggerMixin包含不可序列化的属性(如文件句柄、网络连接),需在类中定义__getstate__和__setstate__方法处理这些属性的序列化逻辑。
内容的提问来源于stack exchange,提问作者sinall

