Uploaded image for project: 'Jira Data Center'
  1. Jira Data Center
  2. JRASERVER-36032

Promise returned by IssueModule.refreshIssue() never finishes in some situations

    XMLWordPrintable

Details

    • Bug
    • Resolution: Fixed
    • Medium
    • 6.2
    • 6.1.1
    • Java API

    Description

      This bug regards the new issue navigator plugin.

      1. A custom code calls IssueModule.refreshIssue() and hooks to the Promise it returns (e.g., via always.)
      2. Before the resulting AJAX call is done, IssueModule.refreshIssue() is called another time (it's not the only possibility that can lead to a problem — see below.)

      Expected behaviour: the hook is eventually called.
      Observed behaviour: the hook is never called.

      What happens

      The normal flow of events:

      1. IssueModule.refreshIssue() is called, it constructs a Deferred object and returns its promise.
      2. It then calls ViewIssueController._update() and puts into arguments the callbacks that resolve/reject the refreshIssue's deferred.
      3. ViewIssueController._update() fetches the issue from the server and adds the fetching deferred to this.updating (a RecurringPromise), which subscribes to the fetching-deferred.
      4. ViewIssueController is subscribed to this.updating, so that once the fetching deferred is finished, this.updating calls ViewIssueController._handleLoadSuccess or ViewIssueController._handleLoadError.
      5. ViewIssueController._handleLoad.* extract the refreshIssue's callbacks from the arguments and call them, so that now anyone who has subscribed to IssueModule.refreshIssue() gets notified.

      The critical part in this flow is for ViewIssueController.updating (a RecurringPromise) to call its callbacks with the right arguments — they should contain the callbacks that notify IssueModule.refreshIssue's promise listeners.

      But if in the meanwhile someone adds another deferred to ViewIssueController.updating, the following happens:

      • the pending deferred in ViewIssueController is aborted — by rejecting the current wrapper deferred (which is unused in the existing scheme) and trying to call abort on the original promise (which it doesn't have in this case);
      • when the original fetch-deferred finishes, ViewIssueController.updating's callbacks are not notified, because the deferred that has triggered the event is not the current one (the current one being the second fetch-deferred.)

      So, the finished event is lost. Note that it can happen if a concurrent request to IssueModule.refreshIssue is made — by some other plugin, for example — or if ViewIssueController.updating is updated by an issue load event.

      From my point of view, the problem is that RecurrentPromise.add() incorrectly handles aborting the existing pending deferred. Apparenty, it should notify its fail and always callbacks, specifying the "right" arguments; for that, RecurrentPromise.add should accept not only the new promise, but the arguments that will be passed to the callbacks once this promise becomes aborted.

      This is a major bug because it makes IssueModule.refresh result quite unusable.

      Attachments

        Issue Links

          Activity

            People

              cdarroch Daz
              ff5eced7cbfd Igor Baltiyskiy
              Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: