Uploaded image for project: 'Confluence Data Center'
  1. Confluence Data Center
  2. CONFSERVER-58735

Asynchronously render attachments when loading a Confluence page

    XMLWordPrintable

Details

    • We collect Confluence feedback from various sources, and we evaluate what we've collected when planning our product roadmap. To understand how this piece of feedback will be reviewed, see our Implementation of New Features Policy.

    Description

      Problem Definition

      Files can be rendered in a Confluence page using different macros, such as the view-file or an internal link as described in Display Files and Images.

      Rendering files within Confluence may be an expensive task specially depending on how many files a page needs to render. Confluence needs to run some tasks on the background before displaying the file in the UI.

      Since these tasks are performed on the same thread that is loading the page, tasks associated to attachments may negatively contribute to the total time a page takes to load.

      Suggested Solution

      If we could perform all the backend processes from these macros asynchronously to the page loading, then it could decrease the time it takes to load the page.
      Note that this would not decrease the total time to load the entire page, but would at least load the content and release the browser to the user while more heavy loading is occurring on the backend.
      This is already in place for the Jira Issues macro and something similar could be implemented here.

      Workaround

      As a workaround, the Future Macro could be used, where available, to asynchronously load heavy content.

      As an example, loading a sample page with 50 view-file macros took 997 ms on a vanilla instance:

      2019-08-19 17:06:00,865 DEBUG [http-nio2-26154-exec-15] [atlassian.util.profiling.UtilTimerStack] log [997ms] - /localhost/display/TS/Target+Page
        [21ms] - UserAccessor.getExistingUserByKey()
        [3ms] - UserAccessor.getUserByName()
          [2ms] - CrowdService.getUser()
            [0ms] - ApplicationDAO.findByName()
            [1ms] - UserDao.findByName()
        [25ms] - PermissionManager.isSystemAdministrator()
          [0ms] - UserAccessor.isDeactivated()
          [15ms] - CrowdService.isUserMemberOfGroup()
            [0ms] - ApplicationDAO.findByName()
            [15ms] - MembershipDao.isUserDirectMember()
          [0ms] - UserAccessor.isDeactivated()
          [0ms] - CrowdService.isUserMemberOfGroup()
            [0ms] - ApplicationDAO.findByName()
            [0ms] - MembershipDao.isUserDirectMember()
          [0ms] - CrowdService.isUserMemberOfGroup()
            [0ms] - ApplicationDAO.findByName()
            [0ms] - MembershipDao.isUserDirectMember()
          [1ms] - DefaultSpacePermissionManager.hasPermissionNoExemptions(SYSTEMADMINISTRATOR, user001, global)
            [0ms] - CrowdService.isUserMemberOfGroup()
              [0ms] - ApplicationDAO.findByName()
              [0ms] - MembershipDao.isUserDirectMember()
        [1ms] - UserAccessor.getExistingUserByKey()
        [0ms] - UserAccessor.getUserByName()
          [0ms] - CrowdService.getUser()
            [0ms] - ApplicationDAO.findByName()
            [0ms] - UserDao.findByName()
        [0ms] - PermissionManager.isSystemAdministrator()
        [749ms] - XW Interceptor: Before defaultStack: /pages/viewpage.action (ViewPageAction.execute())
          [0ms] - UserAccessor.exists()
            [0ms] - CrowdService.getUser()
              [0ms] - ApplicationDAO.findByName()
              [0ms] - UserDao.findByName()
          [0ms] - UserAccessor.getPropertySet()
          [0ms] - SpaceAwareInterceptor.intercept()
          [739ms] - PageAwareInterceptor.intercept()
            [30ms] - PageManager.getPageWithComments()
            [2ms] - PermissionManager.hasPermission()
              [2ms] - DefaultSpacePermissionManager.hasPermissionNoExemptions(VIEWSPACE, user001, TS)
                [0ms] - CrowdService.isUserMemberOfGroup()
                  [0ms] - ApplicationDAO.findByName()
                  [0ms] - MembershipDao.isUserDirectMember()
            [13ms] - PermissionManager.hasPermission()
            [0ms] - PermissionManager.hasPermission()
            [0ms] - CommentAwareInterceptor.intercept()
            [0ms] - UserAwareInterceptor.intercept()
            [0ms] - BootstrapAwareInterceptor.intercept()
            [0ms] - PermissionManager.hasPermission()
            [691ms] - XW Interceptor: After defaultStack: /pages/viewpage.action (ViewPageAction.execute())
              [691ms] - XW Interceptor: After validatingStack: /pages/viewpage.action (ViewPageAction.execute())
                [0ms] - UserAccessor.getPropertySet()
                [445ms] - DefaultRenderer.render
                  [445ms] - DefaultRenderer.renderWithResult
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [1ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [2ms] - PageManager.getPage()
                    [4ms] - PermissionManager.hasPermission()
                    [2ms] - CommentManager.countUnresolvedComments()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - PageManager.getPage()
                    [0ms] - PermissionManager.hasPermission()
                    [2ms] - CommentManager.countUnresolvedComments()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - PageManager.getPage()
                    [0ms] - PermissionManager.hasPermission()
                    [2ms] - CommentManager.countUnresolvedComments()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - PageManager.getPage()
                    [0ms] - PermissionManager.hasPermission()
                    [2ms] - CommentManager.countUnresolvedComments()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [1ms] - PageManager.getPage()
                    [0ms] - PermissionManager.hasPermission()
                    [2ms] - CommentManager.countUnresolvedComments()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - PageManager.getPage()
                    [0ms] - PermissionManager.hasPermission()
                    [3ms] - CommentManager.countUnresolvedComments()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - UserAccessor.getPropertySet()
                    [0ms] - PageManager.getPage()
      
      (...)
      

      The same page took 412 ms to load when all the files are loaded from a single Future macro, giving the user a feeling the page is loading faster while another background job loads the files.

      2019-08-19 17:10:14,634 DEBUG [http-nio2-26154-exec-20] [atlassian.util.profiling.UtilTimerStack] log [412ms] - /localhost/display/TS/Target+Page
        [0ms] - UserAccessor.getExistingUserByKey()
        [0ms] - UserAccessor.getUserByName()
          [0ms] - CrowdService.getUser()
            [0ms] - ApplicationDAO.findByName()
            [0ms] - UserDao.findByName()
        [0ms] - PermissionManager.isSystemAdministrator()
          [0ms] - UserAccessor.isDeactivated()
          [0ms] - CrowdService.isUserMemberOfGroup()
            [0ms] - ApplicationDAO.findByName()
            [0ms] - MembershipDao.isUserDirectMember()
      (...)
      
      
      2019-08-19 17:10:16,382 DEBUG [http-nio2-26154-exec-15] [atlassian.util.profiling.UtilTimerStack] log [502ms] - /localhost/plugins/servlet/futureRenderer
        [1ms] - UserAccessor.getExistingUserByKey()
        [0ms] - PermissionManager.isSystemAdministrator()
          [0ms] - UserAccessor.isDeactivated()
            [0ms] - CrowdService.getUser()
              [0ms] - ApplicationDAO.findByName()
              [0ms] - UserDao.findByName()
          [0ms] - CrowdService.isUserMemberOfGroup()
            [0ms] - ApplicationDAO.findByName()
            [0ms] - MembershipDao.isUserDirectMember()
          [0ms] - UserAccessor.isDeactivated()
          [0ms] - CrowdService.isUserMemberOfGroup()
            [0ms] - ApplicationDAO.findByName()
            [0ms] - MembershipDao.isUserDirectMember()
          [0ms] - CrowdService.isUserMemberOfGroup()
            [0ms] - ApplicationDAO.findByName()
            [0ms] - MembershipDao.isUserDirectMember()
          [0ms] - DefaultSpacePermissionManager.hasPermissionNoExemptions(SYSTEMADMINISTRATOR, user001, global)
            [0ms] - CrowdService.isUserMemberOfGroup()
              [0ms] - ApplicationDAO.findByName()
              [0ms] - MembershipDao.isUserDirectMember()
        [4ms] - ContentEntityManager.getById()
        [1ms] - PermissionManager.hasPermission()
          [0ms] - DefaultSpacePermissionManager.hasPermissionNoExemptions(VIEWSPACE, user001, TS)
            [0ms] - CrowdService.isUserMemberOfGroup()
              [0ms] - ApplicationDAO.findByName()
              [0ms] - MembershipDao.isUserDirectMember()
        [466ms] - DefaultRenderer.render
          [466ms] - DefaultRenderer.renderWithResult
            [0ms] - UserAccessor.getPropertySet()
            [0ms] - UserAccessor.getPropertySet()
            [0ms] - UserAccessor.getPropertySet()
            [0ms] - UserAccessor.getPropertySet()
            [2ms] - PageManager.getPage()
            [12ms] - PermissionManager.hasPermission()
            [3ms] - CommentManager.countUnresolvedComments()
            [0ms] - UserAccessor.getPropertySet()
            [0ms] - UserAccessor.getPropertySet()
            [0ms] - UserAccessor.getPropertySet()
            [0ms] - UserAccessor.getPropertySet()
            [0ms] - PageManager.getPage()
            [0ms] - PermissionManager.hasPermission()
            [5ms] - CommentManager.countUnresolvedComments()
            [0ms] - UserAccessor.getPropertySet()
            [0ms] - UserAccessor.getPropertySet()
            [0ms] - UserAccessor.getPropertySet()
            [0ms] - UserAccessor.getPropertySet()
            [0ms] - PageManager.getPage()
      
      (...)
      

      Attachments

        Issue Links

          Activity

            People

              Unassigned Unassigned
              tmasutti Thiago Masutti
              Votes:
              2 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated: