2011-12-07 53 views
3

這是一個令人費解的問題,這是很難甚至名字,更不用說形容。我將從基本事實開始,然後給出可能相關的背景信息。怪誕與mongoengine ReferenceField

考慮兩個mongoengine文檔模型:

class Bar(Document): 
    # ... 
    # field definitions 
    # ... 
    def bar_func(self): 
     pass # ...or some arbitrary code 


class Foo(Document): 
    bar = ReferenceField(Bar) 

以下是不一致生產我們的生產服務器上的AttributeError

# Assume foo_id references a valid Foo document in Mongo 
# and that its 'bar' reference is to a valid Bar document. 
foo = Foo.objects.with_id(foo_id) 
foo.bar.bar_func() # <-- AttributeError on 'bar_func' 

如果我把錯誤的位置之前正確的調試代碼,將type(foo.bar)評估爲字符串產生<class 'bson.dbref.DBRef'>。顯然,一個DBRef沒有一個bar_func屬性,但爲什麼一個DBRef返回的Bar實例的呢?

進一步調試代碼表明以下條件在ReferenceField.__get__功能未能在mongoengine/fields.py

if isinstance(value, (pymongo.dbref.DBRef)): 
     value = _get_db().dereference(value) 

(pymongo.dbref.DBRef)實際上是bson.dbref.DBRef,這似乎是一樣的type(foo.bar)!爲什麼isinstance失敗?

這就是事情真的怪異:

id(type(foo.bar)) == id(bson.dbref.DBRef) # <-- Evaluates to False! 

換句話說,type(foo.bar)不同bson.dbref.DBRef不是通過直接引用bson.dbref.DBRef獲得的一個。實際上,檢查這兩種類型的__dict__會爲其功能和屬性顯示不同的存儲位置。

注:我會打電話的type(foo.bar)fooDBRef下面方便的返回類型,它由bson.dbref.DBRef引用的類型區分。

爲了進一步調試,我修改了DBRef代碼以添加在創建DBRef類型的時間檢查該系統模塊元類,並且存儲這些模塊中的DBRef一個額外的類屬性的ID的列表。結果顯示,創建fooDBRef時存在的模塊集合爲,與創建裸露的bson.dbref.DBRef類型時存在的模塊集合完全不同。其中一個的所有模塊ID與另一個的所有模塊ID不同。

一些可能相關的因素:

  • 上Apache下出現此錯誤運行mod_wsgi的服務器。
  • 服務器在wsgi下運行兩個不同的Django站點(稱它們爲site_asite_b)。
  • foo是site_a.foo_app.models定義和酒吧在site_b.bar_app.models定義。
  • site_a設置。py在INSTALLED_APPS中有site_b.bar_app
  • 產生錯誤的請求由site_a處理。
  • 模塊sys.modulesfooDBRef創建時,但沒有site_a.*模塊。 bson.dbref.DBRef的情況正好相反。
  • httpd reload錯誤後有時會消失一小會兒,和0-10次嘗試內的某個時候返回。

誰能幫我找出是什麼原因造成fooDBRefbson.dbref.DBRef不同?

回答

4

您是否使用嵌入模式或mod_wsgi的守護進程模式?如果使用mod_wsgi的守護進程模式,您是將每個站點委派給不同的守護進程進程組,然後又強制應用程序在主Python解釋器中運行?

這可能是MongoDB的Python客戶端模塊可能並不在Python子口譯正常工作,特別是當模塊在同一進程中的一個不同的子解釋器使用在相同時間的情況下。

所以,你可以在使用WSGIDaemonProcess/WSGIProcessGroup運行在獨立的守護程序組中的每個站點,然後使用WSGIApplicationGroup用「%{}全球」的說法強迫的Python解釋器爲主的用戶。

注意,迫使使用主解釋的時候爲這兩個網站,你可以不再使用嵌入模式,或讓他們在同一個後臺進程組中的兩個運行。因此,爲什麼你需要強制每個運行在單獨的守護進程組中。

+0

我們使用嵌入模式。我切換到守護進程模式,加入WSGIDaemonProcess,WSGIProcessGroup和WSGIApplicationGroup指示到虛擬主機的條目,並且WSGISocketPrefix指令到配置的根級別。它似乎有效!至少,這個錯誤還沒有發生,而且通常情況下它會有這個問題。我將等待一天左右,確保它消失,然後接受答案。謝謝您的幫助! – Alanyst

+0

我很滿意它現在的作品。再次感謝。 – Alanyst