PERF: only subscribe to a topic once for polls

in the past as views were created and destroyed poll subscriptions would change

this caused a lot of load on messaging bus and uneeded traffic
This commit is contained in:
Sam Saffron 2016-01-06 20:35:27 +11:00
parent bfcb0a52bb
commit 57944a0694
3 changed files with 49 additions and 26 deletions

View File

@ -15,7 +15,7 @@ export default Ember.Controller.extend({
showResultsDisabled: Em.computed.equal("poll.voters", 0),
hideResultsDisabled: Em.computed.or("isClosed", "post.topic.closed", "post.topic.archived"),
@computed("model", "vote")
@computed("model", "vote", "model.voters", "model.options", "model.status")
poll(poll, vote) {
if (poll) {
const options = _.map(poll.get("options"), o => Em.Object.create(o));

View File

@ -1,4 +1,7 @@
import PostView from "discourse/views/post";
import TopicController from "discourse/controllers/topic";
import Post from "discourse/models/post";
import { on } from "ember-addons/ember-computed-decorators";
function createPollView(container, post, poll, vote) {
@ -6,7 +9,7 @@ function createPollView(container, post, poll, vote) {
view = container.lookup("view:poll");
controller.set("vote", vote);
controller.setProperties({ model: Em.Object.create(poll), post });
controller.setProperties({ model: poll, post });
view.set("controller", controller);
return view;
@ -17,13 +20,39 @@ export default {
initialize(container) {
const messageBus = container.lookup("message-bus:main");
Post.reopen({
// we need a proper ember object so it is bindable
pollsChanged: function(){
const polls = this.get("polls");
if (polls) {
this._polls = this._polls || {};
_.map(polls, (v,k) => {
const existing = this._polls[k];
if (existing) {
this._polls[k].setProperties(v);
} else {
this._polls[k] = Em.Object.create(v);
}
});
this.set("pollsObject", this._polls);
}
}.observes("polls")
});
// listen for back-end to tell us when a post has a poll
messageBus.subscribe("/polls", data => {
const post = container.lookup("controller:topic").get('model.postStream').findLoadedPost(data.post_id);
// HACK to trigger the "postViewUpdated" event
Em.run.next(() => post.set("cooked", post.get("cooked") + " "));
TopicController.reopen({
subscribe(){
this._super();
this.messageBus.subscribe("/polls/" + this.get("model.id"), msg => {
const post = this.get('model.postStream').findLoadedPost(msg.post_id);
if (post) {
post.set('polls', msg.polls);
}
});
},
unsubscribe(){
this.messageBus.unsubscribe('/polls/*');
this._super();
}
});
// overwrite polls
@ -32,12 +61,16 @@ export default {
@on("postViewInserted", "postViewUpdated")
_createPollViews($post) {
const post = this.get("post"),
polls = post.get("polls"),
votes = post.get("polls_votes") || {};
post.pollsChanged();
const polls = post.get("pollsObject");
// don't even bother when there's no poll
if (!polls) { return; }
// TODO inject cleanly into
// clean-up if needed
this._cleanUpPollViews();
@ -55,23 +88,11 @@ export default {
pollViews[pollName] = pollView;
});
messageBus.subscribe(`/polls/${this.get("post.id")}`, results => {
if (results && results.polls) {
_.forEach(results.polls, poll => {
if (pollViews[poll.name]) {
pollViews[poll.name].get("controller").set("model", Em.Object.create(poll));
}
});
}
});
this.set("pollViews", pollViews);
},
@on("willClearRender")
_cleanUpPollViews() {
messageBus.unsubscribe(`/polls/${this.get("post.id")}`);
if (this.get("pollViews")) {
_.forEach(this.get("pollViews"), v => v.destroy());
}

View File

@ -81,7 +81,7 @@ after_initialize do
post.custom_fields[VOTES_CUSTOM_FIELD]["#{user_id}"] ||= {}
post.custom_fields[VOTES_CUSTOM_FIELD]["#{user_id}"][poll_name] = options
post.custom_fields[VOTES_CUSTOM_FIELD].each do |user_id, user_votes|
post.custom_fields[VOTES_CUSTOM_FIELD].each do |_, user_votes|
next unless votes = user_votes[poll_name]
votes.each { |option| all_options[option] += 1 }
poll["voters"] += 1 if (available_options & votes.to_set).size > 0
@ -92,7 +92,7 @@ after_initialize do
post.custom_fields[POLLS_CUSTOM_FIELD] = polls
post.save_custom_fields(true)
MessageBus.publish("/polls/#{post_id}", { polls: polls })
MessageBus.publish("/polls/#{post.topic_id}", { post_id: post_id, polls: polls })
return [poll, options]
end
@ -128,7 +128,7 @@ after_initialize do
post.save_custom_fields(true)
MessageBus.publish("/polls/#{post_id}", { polls: polls })
MessageBus.publish("/polls/#{post.topic_id}", {post_id: post.id, polls: polls })
polls[poll_name]
end
@ -350,7 +350,7 @@ after_initialize do
post.save_custom_fields(true)
# publish the changes
MessageBus.publish("/polls/#{post.id}", { polls: polls })
MessageBus.publish("/polls/#{post.topic_id}", { post_id: post.id, polls: polls })
end
end
else
@ -370,7 +370,9 @@ after_initialize do
# tells the front-end we have a poll for that post
on(:post_created) do |post|
next if post.is_first_post? || post.custom_fields[POLLS_CUSTOM_FIELD].blank?
MessageBus.publish("/polls", { post_id: post.id })
MessageBus.publish("/polls/#{post.topic_id}", {
post_id: post.id,
polls: post.custom_fields[POLLS_CUSTOM_FIELD]})
end
add_to_serializer(:post, :polls, false) { post_custom_fields[POLLS_CUSTOM_FIELD] }