3

これは、説明するどころか、名前を付けることさえ困難な不可解な問題です。重要な事実から始めて、関連する可能性のある背景情報を示します。

2 つの 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'>. 明らかに a には属性DBRefがありませんが、のインスタンスではなく a が返されるのはなぜですか?bar_funcDBRefBar

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)とは異なります。 実際、これら 2 つの型を調べると、関数とプロパティの異なるメモリ位置が示されます。bson.dbref.DBRefbson.dbref.DBRef__dict__

注:type(foo.bar) fooDBRefによって参照される型と区別するために、便宜上、以下では によって返される型と呼びますbson.dbref.DBRef

さらにデバッグするためにDBRef、型の作成時にシステム モジュールを検査するメタクラスを追加するようにコードを変更しDBRef、それらのモジュールの ID のリストを の追加のクラス属性に格納しますDBRef。結果は、が作成されたときに存在するモジュールのセットが、ベアタイプが作成されたときに存在するモジュールのセットとfooDBRef完全に異なることを示しています。bson.dbref.DBRef一方のすべてのモジュール ID は、もう一方のすべてのモジュール ID とは異なります。

関連する可能性のある要因:

  • このエラーが発生するサーバーは、Apache で mod_wsgi を実行しています。
  • サーバーは、wsgi の下で 2 つの異なる Django サイトを実行します (それらsite_aを および と呼びますsite_b)。
  • Foo は で定義されsite_a.foo_app.models、Bar は で定義されていsite_b.bar_app.modelsます。
  • site_asettings.py にsite_b.bar_appINSTALLED_APPS.
  • エラーを生成する要求は によって処理されsite_aます。
  • が作成されたときにsite_b.*モジュールがありましたが、モジュールはありませんでした。については逆です。sys.modulesfooDBRefsite_a.*bson.dbref.DBRef
  • エラーが発生した後、httpd reloadしばらくの間エラーが解消され、0 ~ 10 回の試行で元に戻ることがあります。

fooDBRefとの違いの原因を突き止めるのを手伝ってくれる人はいbson.dbref.DBRefますか?

4

1 に答える 1

4

mod_wsgi の組み込みモードまたはデーモン モードを使用していますか? mod_wsgi のデーモン モードを使用している場合、各サイトを別のデーモン プロセス グループに委任してから、アプリケーションをメインの Python インタープリターで強制的に実行していますか?

特にモジュールが同じプロセスの別のサブ インタープリターで同時に使用されている場合、mongodb Python クライアント モジュールが Python サブ インタープリターで正しく動作しない場合があります。

そのため、WSGIDaemonProcess/WSGIProcessGroup を使用して個別のデーモン プロセス グループで各サイトを実行し、'%{GLOBAL}' の引数で WSGIApplicationGroup を使用して Python メイン インタープリターのユーザーを強制する必要がある場合があります。

両方のサイトでメイン インタープリターの使用を強制すると、組み込みモードを使用できなくなったり、両方を同じデーモン プロセス グループで実行したりすることができなくなることに注意してください。したがって、それぞれを個別のデーモンプロセスグループで強制的に実行する必要があるのはなぜですか。

于 2011-12-08T01:12:27.810 に答える