2017-03-01 9 views
4

ユーザーが製品を作成してコメントを付けることができる単純なアプリケーションがあるとします。商品やコメントのスキーマは次のようになります。mongooseミドルウェアで従属文書を削除するときの同時性問題

var productSchema = new mongoose.Schema({ 
    author_id: ObjectId, 
    description: String 
}); 

var commentSchema = new mongoose.Schema({ 
    product_id: ObjectId, 
    author_id: ObjectId, 
    message: String 
}); 

すべてのコメントが既存の製品を参照していることを確認します。これは、簡単にフック保存マングースの前で行うことができます。

commentSchema.pre("save", function(next) { 
    Product.count({ _id: this.product_id }, function(err, count) { 
    if (err || !count) { 
     next(new Error("Could not find product")); 
    } else { 
     next(); 
    } 
    }); 
}); 

また、ユーザーが製品を削除した場合、当社はその製品のすべてのコメントを削除したいです。

productSchema.pre("remove", function(next) { 
    Comment.remove({ product_id: this._id }, next); 
}); 

しかし、ユーザーAが製品を削除すると同時に、ユーザーBがその製品についてコメントするとどうなりますか?

以下が発生する可能性があります:

Call pre save hook for new comment, and check if product exists 
Call pre remove hook for product, and remove all comments 
In pre save hook, done checking: product actually exists, call next 
Comment saved 
In pre remove hook, done removing comments: call next 
Product removed 

最終結果は、我々が存在しない製品を指し、コメントを持っているということです。

これは、これが発生する原因の多くの場合の1つに過ぎません。どのようにこのコーナーケースを防ぐことができますか?

+0

ユーザーがコメントできない場所で遅延が発生する可能性があります。私はこれが何をスタックだと思います – pudility

答えて

0

var deletingPostOfId = null; 
 

 
function deletePost(id) { 
 
    deletingPostOfId = id; 
 
    
 
    Post.remove({_id: id}, function() { 
 
     deletingPostOfId = null; 
 
    }) 
 
} 
 

 
function createComment(comment) { 
 
    if(comment.post_id !== deletingPostOfId) Comment.save(...) 
 
}

2

マングースpost hookを使用する代わりにpre hook秒の問題を解決sのようだ:

commentSchema.post("save", function(comment) { 
    Product.count({ _id: comment.product_id }, function(err, count) { 
    if (err || !count) comment.remove(); 
    }); 
}); 

productSchema.post("remove", function(product) { 
    Comment.remove({ product_id: product._id }).exec(); 
}); 

Iという(これは、4つの可能なケースを考慮することによって問題を解決する理由を見てみましょう考えることができる):

1) Comment gets saved before product is removed 
2) Comment gets saved after product is removed but before post remove hook 
3) Comment gets saved after product is removed and while post remove hook is 
    executing 
4) Comment gets saved after product is removed and post remove hook executed 
------------------------------------------------------------------------ 
In case 1, after the product is removed, the comment will be removed in the post 
remove hook. 
In case 2, same, post remove hook will remove the comment. 
In case 3, the comment post save hook will successfully remove the comment. 
In case 4, same as case 3, post save hook removes the comment. 

しかし、まだ少しの問題があります:製品が削除された後、しかしpost remove hookが実行される前に何か悪いことが起きたらどうなりますか?電気が消えてしまうか、そういうものがあると言います。その場合、存在しない製品を参照するコメントが表示されます。これを修正するには、pre remove hookを製品に保つことができます。これにより、製品が削除されるのは、すべての従属コメントが削除された場合のみです。しかし、OPで指摘されているように、これは同時実行性の問題を処理しません。つまり、post remove hookが救助に来ます!だから我々は両方が必要:

productSchema.pre("remove", function(next) { 
    var product = this; 
    Comment.remove({ product_id: product._id }, next); 
}); 

productSchema.post("remove", function(product) { 
    Comment.remove({ product_id: product._id }).exec(); 
}); 

私はこれがそれたことを望むが、私はまだ非常にリモートの場合を考えることができますどのようなコメントは、製品を除去し、post remove hookが実行された後に保存されますが、ちょうどコメントの前にpost save hook実行入った場合(これはコメントを削除する)ライトが消える!私たちは存在しない製品を指すコメントで終わります!これが起こる可能性は信じられないほど低いですが、それでも..

もし誰かが並行処理を扱う良い方法を考えることができたら、私の答えを改善してください。

関連する問題