1

と仲良く@ndb.toplevel遊べる@ndb.transactionalでしょうか?

私が達成したいのは、entity.put_async()呼び出しを含むトランザクションですが、先物を明示的に待つ必要がないという便利さです。@ndb.toplevel通常はこれを行いますが、別の SO の質問は、トランザクションと組み合わせることはできないことを示唆しているようです: 「ndb トップレベルはトランザクションを壊しますか?」

これは、App Engine のドキュメントのどこにも明示的に文書化されているのを見つけることができません。put_async()その質問に示されているアサーション エラーを再現することはできますが、呼び出しが失敗して問題がないかどうかを確認するためにいくつかのテストを作成しました。ただし、データが失われる可能性があるため、ndb をよく知っている人からここでより具体的な回答を得るとよいでしょう。

簡単なテスト コードを以下に示します。ndb.toplevelndb.transactionalデコレータの両方を削除すると、予想どおり、テストは失敗します。ただし、デコレータのみを使用してndb.transactionalデコレータを省略したndb.toplevel場合、テストはパスしますが、これは予期されていません。ndb.transactionalこれは、呼び出しが完了するのに十分な時間があるのに十分なオーバーヘッドがあるだけでput_async()、保証がないので、予期せずに失敗する可能性があるのではないかと心配しています。

class AsyncTestModel(ndb.Model):
    data = ndb.StringProperty(indexed=True)

@ndb.toplevel
def start_test():
    for _ in range(100):
        test()

    # Check we wrote all the entities
    time.sleep(30)
    entities = AsyncTestModel.query().fetch()
    assert(len(entities) == 1000)


@ndb.transactional(xg=True)
def test():
    for _ in range(10):
        x = AsyncTestModel()
        x.data = make_random_string(1000)
        x.put_async()
4

1 に答える 1

4

使用するだけでテストに合格するという事実@ndb.transactionalは、予想される動作です。トランザクションが部分的に適用されないようにするには@ndb.transactional、すべての要求が完了するまで待ちます。

そのため、コードfor _ in range(100): test()は各反復でトランザクションが終了するのを待ちます。

したがって、次のテストに合格します。

@ndb.transactional(xg=True)
def test():
    for _ in range(10):
        x = AsyncTestModel()
        x.data = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(1000))
        x.put_async()

for x, _ in enumerate(range(100)):
    test()
    assert(AsyncTestModel.query().count() == (x + 1) * 10)

注: トランザクションで非同期クエリを使用する場合は、@ndb.transactional_async(ドキュメントはこちら) を参照してください。

于 2015-10-14T07:12:19.447 に答える