Customers page hangs for non-admin agents when project has many organizations due to N+1 query in CustomerOrganizationMemberQStoreImpl.isMemberOfAnyOrganizationInProject()

XMLWordPrintable

    • Type: Bug
    • Resolution: Unresolved
    • Priority: Low
    • None
    • Affects Version/s: 10.3.19
    • Component/s: Customer Portal
    • 3
    • Severity 2 - Major
    • 22

      Issue Summary

      When a non-admin service desk agent navigates to the Customers page (/projects/PKEY/customer) on a project with 65+ organizations, the page hangs indefinitely or times out. The /search endpoint fails with net::ERR_ABORTED — no response headers are received.

      The root cause is an N+1 database query pattern in the "Customer Portal Only" permission check. For each organization in the project, the server executes a separate SQL query via CustomerOrganizationMemberQStoreImpl.isMemberOfAnyOrganizationInProject() — a COUNT join across AO_54307E_ORGANIZATION_MEMBER, AO_54307E_ORGANIZATION, and AO_54307E_ORGANIZATION_PROJECT — each in its own transaction.

      Admin users are not affected because hasPermission() short-circuits before reaching CustomerPortalOnlySecurityTypeImpl, returning true immediately without executing any organization membership queries.

      Thread dumps confirm the same stack trace across multiple intervals:
       
       com.mysql.cj.jdbc.ClientPreparedStatement.executeQuery()com.atlassian.pocketknife.internal.querydsl.DatabaseAccessorImpl.runInTransaction()com.atlassian.servicedesk.internal.feature.organization.dao.CustomerOrganizationMemberQStoreImpl.isMemberOfAnyOrganizationInProject()com.atlassian.servicedesk.internal.feature.organization.member.CustomerOrganizationMemberManagerImpl.isMemberOfAnyOrganizationsInProject()com.atlassian.servicedesk.internal.permission.security.type.CustomerPortalOnlyPermissionChecker.isMemberOfAnyOrganisationsInProject()CustomerPortalOnlyPermissionChecker.allowUserToAccessPortal()CustomerPortalOnlyPermissionChecker.hasCustomerPortalOnlyPermissionForProject()CustomerPortalOnlyPermissionChecker.hasCustomerPortalOnlyPermission()CustomerPortalOnlySecurityTypeImpl.hasPermission()DefaultPermissionSchemeManager.hasSchemePermission()DefaultPermissionManager.hasPermission()WorkflowBasedPermissionManager.hasPermission()ThreadLocalCachingPermissionManager.hasPermission()ApplicationRequiredPermissionManager.hasPermission()
      This is the same root cause as https://jira.atlassian.com/browse/JSDSERVER-5222 — same class, same method, same O(N) pattern — but triggered via /projects/PKEY/customer (iterating over organizations within a project) instead of GET /portals (iterating over service desks). The fix for JSDSERVER-5222 did not cover this code path. https://jira.atlassian.com/browse/JRACLOUD-80816 confirms the same symptom exists on Cloud.

      Steps to Reproduce

      1. Set up a JSM DC instance running version 10.3.19
      1. Create a JSM project with the "Customer Portal Only" permission security type configured
      1. Link 65+ organizations to the project
      1. Create an agent user (non-admin) with only the Service Desk Team role on the project
      1. Log in as the agent user
      1. Navigate to Project → Customers (/projects/PKEY/customer)

      Expected Results

      The Customers page loads and displays all organizations and customers.

      Actual Results

      The page hangs indefinitely or times out. The /search endpoint (/rest/servicedesk/1/pages/people/customers/pagination/PKEY/search?query=&page=1) fails with net::ERR_ABORTED — no response headers are received.

      Workaround

      • Remove the "Customer Portal Only" security type from the project's permission scheme and replace it with a standard security type (e.g., Project Role → Service Desk Customers). This eliminates the N+1 query loop entirely.
      • Alternatively, grant affected agents the "Service Project Administrator" role. This causes hasPermission() to short-circuit before reaching CustomerPortalOnlySecurityTypeImpl. Note: this widens the permission scope and should be treated as a temporary measure.
      • Enable dark feature sd.use.global.cache.for.permission.check.enabled (available since JSM 10.3.2+) for partial relief through improved caching, but this does not address the fundamental N+1 pattern.

      Versions Tested

      Please confirm all versions that have been tested for this issue, and indicate whether the tested version is affected or not affected, below: 

      Testing Requirements Version Affected Version
      Customers Reported Version 10.3.19 Yes 
      Most Recent Bug-Fix Release    
      Previous Major Release    
      Most Recent LTS    
      Previous Supported LTS    
      Other Versions..    
      (Add rows as needed)    

              Assignee:
              Unassigned
              Reporter:
              Faizan Ashraf
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

                Created:
                Updated: