FIX: eliminate race condition creating posts

FIX: correct message bus posting
This commit is contained in:
Sam 2014-07-30 14:04:27 +10:00
parent e7e70d14da
commit 9147af1d62
2 changed files with 24 additions and 4 deletions

View File

@ -1,6 +1,10 @@
# Cross-process locking using Redis. # Cross-process locking using Redis.
class DistributedMutex class DistributedMutex
def self.synchronize(key, redis=nil, &blk)
self.new(key, redis).synchronize(&blk)
end
def initialize(key, redis=nil) def initialize(key, redis=nil)
@key = key @key = key
@redis = redis || $redis @redis = redis || $redis

View File

@ -3,6 +3,7 @@
require_dependency 'rate_limiter' require_dependency 'rate_limiter'
require_dependency 'topic_creator' require_dependency 'topic_creator'
require_dependency 'post_jobs_enqueuer' require_dependency 'post_jobs_enqueuer'
require_dependency 'distributed_mutex'
class PostCreator class PostCreator
@ -54,7 +55,7 @@ class PostCreator
@topic = nil @topic = nil
@post = nil @post = nil
Post.transaction do transaction do
setup_topic setup_topic
setup_post setup_post
rollback_if_host_spam_detected rollback_if_host_spam_detected
@ -66,21 +67,24 @@ class PostCreator
update_user_counts update_user_counts
create_embedded_topic create_embedded_topic
publish
ensure_in_allowed_users if guardian.is_staff? ensure_in_allowed_users if guardian.is_staff?
@post.advance_draft_sequence @post.advance_draft_sequence
@post.save_reply_relationships @post.save_reply_relationships
end end
if @post if @post && @post.errors.empty?
publish
PostAlerter.post_created(@post) unless @opts[:import_mode] PostAlerter.post_created(@post) unless @opts[:import_mode]
handle_spam unless @opts[:import_mode]
track_latest_on_category track_latest_on_category
enqueue_jobs enqueue_jobs
BadgeGranter.queue_badge_grant(Badge::Trigger::PostRevision, post: @post) BadgeGranter.queue_badge_grant(Badge::Trigger::PostRevision, post: @post)
end end
if @post && (@post.errors.present? || @spam)
handle_spam unless @opts[:import_mode]
end
@post @post
end end
@ -111,6 +115,18 @@ class PostCreator
protected protected
def transaction(&blk)
Post.transaction do
if new_topic?
blk.call
else
# we need to ensure post_number is monotonically increasing with no gaps
# so we serialize creation to avoid needing rollbacks
DistributedMutex.synchronize("topic_id_#{@opts[:topic_id]}", &blk)
end
end
end
# You can supply an `embed_url` for a post to set up the embedded relationship. # You can supply an `embed_url` for a post to set up the embedded relationship.
# This is used by the wp-discourse plugin to associate a remote post with a # This is used by the wp-discourse plugin to associate a remote post with a
# discourse post. # discourse post.