Mongoengine文档在并发下的一致性
我正在尝试创建一个虚拟的包装类(一个mongoengine文档),这个类要实现Redis哈希的接口。比如说:
class HashModel(mongoengine.Document):
'''
Represents a dictionary with a name.
Interface similar to Redis Hashes
'''
name = mongoengine.StringField()
adict = mongoengine.DictField()
def safe_reload(self): # because it fails if no object present
try: self.reload()
except:pass
def fix_key(self, key): # for mongoengine validation ( if you really read my code, please also answer why does mongoengine need that )
return key.replace(".","").replace("$","")
def hset(self, key, value):
self.safe_reload()
self.adict["%s" % self.fix_key(key)] = value
self.save(safe=True)
return True
def hexists(self, key):
self.safe_reload()
key = "%s" % self.fix_key(key)
return key in self.adict
然后,我使用celery来执行一些任务。在这之前,我会初始化一个HashModel对象,任务会在这个对象上进行一些操作。但是因为使用了多进程,我发现了一些不一致的情况。不同的进程“获取”的对象“快照”是不一样的,这其实也是很正常的。为了绕过这个问题,我每次都重新初始化这个对象,这样每次都能得到一个“几乎”全新的快照。
问题是:有没有办法避免重新初始化?我可以在上面的类中添加一些代码吗?如果可以,应该添加什么代码呢?
编辑: 答案是:看起来mongoengine.Document.reload()函数可以做到这一点。我更新了我的代码,展示了与我下一个问题相关的所有内容:
回到celery任务中,出现了这样一个问题:当我执行hset(a_key, a_value)后,稍后再检查这个键是否存在时,有时hexists(a_key)会返回False。即使我强制执行hset,像这样:
while True:
self.handler.hset(a_key, a_value)
if self.handler.hexists(a_key):
break
在某个时刻(并没有在其他地方删除a_key),有时hexists(a_key)仍然会返回False。这是怎么回事呢???
1 个回答
1
这是一个纯粹的竞争条件问题。我的celery工作进程可能会同时获取一个实例,并对它进行不同的操作,然后再保存,这样就没有一致性了。