thunderbird / thunderbird/thunderbird-android

Handle failing 'pending commands'

Open
#4,450 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

type: architecture
Dominant language
Kotlin
Stars
14k
Forks
2.8k
Avg merge
3d 3h
Merged PRs (30d)
57

Description

Whenever K-9 Mail is asked to modify a message (e.g. mark as read, move to another folder), the local message is updated and a PendingCommand is created that describes the operation to be performed on the server. This queue of pending commands is persisted in the database because it might be a while before the device is online again and the operations can be performed on the server.

When the queue is processed there's currently three error cases that can occur:

  • The command fails with a MessagingException with isPermanentFailure() returning true. This happens when the backend is sure repeating the command won't change the outcome (failure). In that case the command is removed from the queue and the next command is processed.
  • The command fails with a MessagingException with isPermanentFailure() returning false. This can happen on e.g. network errors or authentication failures. In this case processing the queue is halted. The assumption is that all other commands will fail, too.
  • The command fails with any other exception. In this case processing the queue is halted. This case isn't explicitly handled. An outer layer catches Exception and prevents the app from crashing.

The problem with the current approach is that (repeatedly) failing commands that are not removed from the queue will block it forever. Every time the queue is processed (e.g. before a sync) the command will fail and all following commands will never be executed. The local changes will still be made. So in K-9 Mail it looks like everything is working fine.

The problem with removing failing commands is that we currently don't revert local changes or notify the user about the error.
In theory there could also be dependencies between commands in the queue (a later command depends on the successful execution of a previous command). I'm not sure we currently support such a scenario. But it's something to be aware of. And it's something that makes removing commands from the queue without causing additional issues much more work.

I think a good first step would be to remove each command that is failing with anything other than a MessagingException (we might have to handle IOException like MessagingException with isPermanentFailure() returning false because backends might not wrap them).
Without reverting the local change and notifying the user it's not great. But it's strictly better than blocking the pending commands queue forever.

Suggestions for a strategy to properly handle failing pending commands are very welcome.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The issue does not name a file or test. Start by locating the pending-command queue processing and its exception handling; compare the three failure cases described, then verify that non-MessagingException failures no longer block later commands while rollback, user notification, and command dependencies remain explicit follow-up concerns.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, kotlin
Domain
mobile-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.