freedomofpress / securedrop-client

a Qt-based GUI for SecureDrop journalists 📰🗞️
GNU Affero General Public License v3.0
41 stars 40 forks source link

Replies are sometimes displayed out of order #653

Open eloquence opened 4 years ago

eloquence commented 4 years ago

STR 1 - For SendReplyJobTimeoutError

  1. Apply this diff so that sometimes a reply fails:
--- a/securedrop_client/api_jobs/uploads.py
+++ b/securedrop_client/api_jobs/uploads.py
@@ -28,6 +28,11 @@ class SendReplyJob(ApiJob):
         database and return the reply uuid string. Otherwise raise a SendReplyJobException so that
         we can return the reply uuid.
         '''
+        import random
+        if random.choice([0, 1]):
+            self.remaining_attempts = 0
+            raise SendReplyJobTimeoutError('test', self.reply_uuid)
+
         try:
             draft_reply_db_object = session.query(DraftReply).filter_by(uuid=self.reply_uuid).one()
             source = session.query(Source).filter_by(uuid=self.source_uuid).one()
  1. Send many replies so that there are some successful and once one fails see the conversation reorder like so:

Screenshot from 2020-02-11 11-40-00

  1. Wait until the reply succeeds (because of auto-resume when sync succeeds) and see that the failed reply moves to a successful state

Screenshot from 2020-02-11 11-40-13

  1. Wait until the next sync and see the replies get reordered correctly:

Screenshot from 2020-02-11 11-40-25

STR 2 - For SendReplyJobError

  1. Apply this diff so that sometimes a reply fails:
--- a/securedrop_client/api_jobs/uploads.py
+++ b/securedrop_client/api_jobs/uploads.py
@@ -28,6 +28,11 @@ class SendReplyJob(ApiJob):
         database and return the reply uuid string. Otherwise raise a SendReplyJobException so that
         we can return the reply uuid.
         '''
+        import random
+        if random.choice([0, 1]):
+            self.remaining_attempts = 0
+            raise SendReplyJobError('test', self.reply_uuid)
+
         try:
             draft_reply_db_object = session.query(DraftReply).filter_by(uuid=self.reply_uuid).one()
             source = session.query(Source).filter_by(uuid=self.source_uuid).one()

repeat steps 2-4 above

redshiftzero commented 4 years ago

Problem 1: Replies are prioritized low in the queue

Fixes:

Problem 2: conversation slow to update

Fix:

eloquence commented 4 years ago

462 (we're clogging up the queue with Metadata jobs)

Agreed, but I'm not sure that this is the entire cause of the reply slowness I'm seeing -- I was able to reliably reproduce this over the course of a couple of minutes, where it would alternate between fast (2.5 seconds) and slow (15-20 seconds), without me initiating any sync of my own during this time.

eloquence commented 4 years ago

Performance is significantly better in the latest nightly build, I'm now seeing >1st replies transition all the way to "sent" in the 6-8 second range. Perhaps this will go down further once all the metadata sync changes have landed.

We still have the ordering problem; the order is only "eventually correct", but initially replies appear out of order.

Also worth noting: Out of 20 replies or so I encountered one random failure. I would have expected it to go to "Failed to send" after lots more retries, but it basically transitioned to "Failed" almost immediately.

ntoll commented 4 years ago

Is this not fixed by #688..?

redshiftzero commented 4 years ago

yep you're right, I have not observed this behavior for some time. Closing and let's reopen if we see this again.

sssoleileraaa commented 4 years ago

I just updated the description with the latest STR and reopening because this is not resolved yet.

ntoll commented 4 years ago

Aha..! :smile:

eloquence commented 4 years ago

I've not tested your STR yet Allie, but yay, generally speaking, replies are a lot more reliable now (in Qubes). I'm not seeing the ordering issue during normal use, and replies are sent quite quickly.

sssoleileraaa commented 4 years ago

When someone gets a chance, could you run through the updated STR to confirm that this is a bug we need to fix: https://github.com/freedomofpress/securedrop-client/issues/653#issue-535526020 -- I'm not a 100% sure that @ntoll has already done so

sssoleileraaa commented 4 years ago

today, when running through the STR I saw the same issue: Screenshot from 2020-02-24 17-05-22

sssoleileraaa commented 4 years ago

Note: these replies stay out of order even after a pending reply turns to a successful reply. when i close the client and reopen the replies are reordered correctly:

Screenshot from 2020-02-24 17-10-01

It appears the bug is somewhere within update_conversation

ntoll commented 4 years ago

So... @creviera yes I did manage to recreate but functional tests have taken up my time. However, now they're done I'll look into this.

I've just observed the following (problem) behaviour by following the STR:

I agree with @creviera that the error is in 'update_conversation' and that it's not so much a bug, as an omission to deal with how to order pending or failed replies (which won't yet be known by the server, so the message order when we next refresh will be correct but won't contain those unknown replies).

My suggested fix (which I'll go ahead and implement so we can at least confirm my hunch is correct -- we can change the fix's behaviour during review of the impending PR) is:

Sound like a plan..?

Give me 10 mins to get a PR in fight with a potential fix / unit tests to prove things behave as expected.

redshiftzero commented 4 years ago

OK having trouble reproducing this due to #820 but looking at the logic: we have logic to reorder drafts to ensure consistent ordering of interleaved successful replies and drafts. This is performed at sync time, and at reply send time when the reply a successful. That means that the local order we have stored should be correct. In order for this order to be shown in the UI, we need to enter update_conversation for the reordering logic to run at the UI level. Is that happening? I'm not seeing where if so - it seems like only on source click and on recreation of the conversation view. That would explain the behavior.

moved the below to issue #821 to focus convo on the reordering bug (my bad)

Question: do we really need add_reply_from_reply_box? This is one path to widgets getting added to the conversation view outside of calls to update_conversation. It seems unnecessary now: in on_reply_sent here we should be able to call update_conversation instead of this additional method add_reply_from_reply_box (source.collection has the DraftReply object which will be created immediately when we click send).

sssoleileraaa commented 4 years ago

add_reply_from_reply_box is called when the user clicks "Send". Without it, we won't immediately see replies in the ConversationView. If we want to remove it, I think we will need to emit a new signal from the Controller after it creates the new DraftReply in response to the user clicking "Send" and then the GUI will have to respond by adding a new reply widget to the conversation view.

I think this is more of a refactor, but I'm not sure it's related to this issue, because update_conversation uses an index to reorder conversation items if the index no longer matches its GUI placement in the conversation, see https://github.com/freedomofpress/securedrop-client/blob/b75db2d9d937060d87dfe54755615f89734b2b0a/securedrop_client/gui/widgets.py#L2758-L2768

The strange reordering behavior only seems to be introduced once a reply is failed, which is why I no longer see STR #1 reported in this issue after making this change: https://github.com/freedomofpress/securedrop-client/pull/818

redshiftzero commented 4 years ago

In order to verify if this was a UI only issue or not I decided to double check using the debug logging here along with logging the current value of source.conversation when drawing the conversation view. I noticed that the interaction_count was not getting updated on the source, which led me to #829. From the comment:

We use the file_counter on each Reply, Message, File, and DraftReply object to order the conversation view. We expect a unique file_counter for Reply, Message, and File objects since they are retrieved from the server. For DraftReply, we don't have that unique constraint, and we instead expect the file_counter to be the interaction_count at the time of send. If we do not update the interaction_count after each successful reply send, future drafts will have an interaction_count that is too low, leading to incorrectly ordered drafts until a metadata sync completes (the metadata sync is the place where the source object is updated from the server).

rocodes commented 2 years ago

I've noticed a sort-of a recurrence of this issue, but no failed reply is required. (Unreliable STR: send lots of replies in quick succession, can observe mis-ordered messages some of the time, order corrects after sync). I'm not sure if it merits re-opening this issue, since it basically involves quickly sending many consecutive replies, and is resolved after a sync, but documenting it here.)

(sometimes the mis-ordering is worse than this, sometimes it doesn't occur at all even with upwards of 15 messages): order

(reordered correctly after a sync) order2

eloquence commented 2 years ago

I saw this once as well during recent QA but didn't write it up, thanks for noting it here. I'd say let's definitely reopen, defer to Allie on priority, but I think it'd be good to know at least what's causing it.