GraphQL query limits and dynamic limits

Understanding GraphQL query limits, dynamic limits, and subquery limits.

Skedulo GraphQL provides flexible query limits to balance performance and data access requirements. This page explains the different limit behaviors and how to use them effectively.

Using the limit parameter

The limit parameter allows you to request up to 10,000 top-level records, with dynamic limits applied based on query complexity to protect system performance.

Example:

{
  jobs(limit: 1200) {
    edges {
      node {
        UID
        Name
        JobStatus
        JobAllocations(limit: 25) {
          UID
          Status
        }
      }
    }
  }
}

Dynamic query limits

When using the limit parameter, the system calculates a dynamic maximum limit based on query complexity to prevent resource exhaustion.

Dynamic limit calculation

The dynamic limit is calculated based on query complexity to protect system performance. The exact calculation considers factors such as the number of fields, nested relationships, query depth, and the values of subquery limits in nested relationships.

The minimum dynamic limit is 200 no matter how complex a query is. This is to ensure smooth migration from the first parameter.

Response header

The calculated dynamic limit is returned in the X-Skedulo-Dynamic-Query-Limit response header, allowing you to understand the maximum limit for your specific query.

Subquery limits

When using the limit parameter at the top level, any child HasMany relationships that don’t have an explicit limit parameter will have a implicit limit applied automatically.

Subquery limit rules

  • Maximum: 2000 records
  • Default: 20 records
  • Automatic: When using top-level limit, all HasMany relationships automatically have a limit parameter applied (defaults to 20 if not specified)
  • No Pagination: Unlike top-level queries, subqueries on HasMany relationships do not support pagination
  • Impact: The subquery limit value affects the parent query’s dynamic limit calculation. This is usually the most significant factor affecting the dynamic limit.

Example with subquery limits

{
  jobs(limit: 600) {
    edges {
      node {
        UID
        Name
        JobAllocations {
          UID
          Status
        }
        JobOffers(limit: 10) {
          UID
          Status
        }
      }
    }
  }
}

Important: Note that subqueries on HasMany relationships (like JobAllocations and JobOffers) do not support pagination. You must set an appropriate limit that covers all the records you need, as there’s no way to fetch additional pages of subquery results.

Error handling

Query complexity limit exceeded

When a query with top-level limit exceeds the dynamically calculated limit, the system returns a query_complexity_limit_exceeded error with details about:

  • The requested limit
  • The maximum allowed limit for that query
  • The maximum allowed limit is also returned in the X-Skedulo-Dynamic-Query-Limit response header

You can resolve the error by reducing the value of the limit parameter or reducing the amount of nested data requested by the query.

Best practices

Testing dynamic limits

  1. Start with smaller limits: Begin with conservative limit values and increase gradually
  2. Monitor response headers: Check the X-Skedulo-Dynamic-Query-Limit header to understand your query’s maximum limit
  3. Test query structure: Add fields and relationships incrementally to understand their impact on the maximum dynamic limit
  4. Use appropriate subquery limits: Set reasonable limits for HasMany relationships to avoid excessive impacts on the dynamic limit. Remember that subqueries don’t support pagination, so choose limits that cover your data needs.

Query optimization

  1. Minimize field selection: Request only the fields you need to reduce resource usage.
  2. Limit nested relationships: Be selective about which relationships to expand.
  3. Keep subquery limits small: Set subquery limits to reasonable values based on the data patterns you have. Since subqueries don’t support pagination, choose limits that balance your data needs with the impact on the top-level dynamic limit.
  4. Use filters: Apply EQL filters to reduce the result set size
  5. Consider pagination: Consider using pagination to retrieve only as much as you need at a time

Determining limits at runtime for dynamically generated queries

When you build GraphQL queries programmatically or receive queries from external sources, the shape of the query and therefore its complexity may not be known in advance. In these cases, follow this approach to determine the appropriate dynamic limit:

  1. Make an initial query with a limit of 200
  2. Check the response header X-Skedulo-Dynamic-Query-Limit to determine the maximum allowed limit for that query
  3. Use the determined limit in subsequent queries to fetch the remaining records efficiently

This approach ensures you can safely determine the dynamic limit without exceeding it, while maximizing the number of records retrieved in follow-up queries.

Examples

Simple query with limit parameter

{
  jobs(limit: 500) {
    edges {
      node {
        UID
        Name
        JobStatus
        Start
        Duration
      }
    }
  }
}

Complex query with subquery limits

{
  jobs(limit: 800) {
    edges {
      node {
        UID
        Name
        JobStatus
        JobAllocations(limit: 10) {
          UID
          Status
          Resource {
            Name
            UID
          }
        }
        JobOffers {
          UID
          Status
        }
      }
    }
  }
}

Query with filters and limits

{
  jobs(limit: 1000, filter: "JobStatus == 'Queued'", orderBy: "Start ASC") {
    edges {
      node {
        UID
        Name
        JobStatus
        Start
        JobAllocations {
          UID
          Status
        }
      }
    }
  }
}

First parameter (deprecated)

The first parameter is deprecated and should not be used. If you use first (or leave out the limit parameter), Skedulo GraphQL returns a maximum of 200 records per query.

Key differences from the limit parameter:

  • Fixed limit: Always 200 records maximum
  • No dynamic limits: No complexity-based calculations
  • No subquery limits: HasMany relationships don’t have automatic limits applied
  • No response header: No X-Skedulo-Dynamic-Query-Limit header provided

Example with first parameter:

{
  jobs(first: 200) {
    edges {
      node {
        UID
        Name
        JobStatus
      }
    }
  }
}

Migrating from first parameter to limit parameter

Migration: We recommend migrating from the first parameter to the limit parameter to take advantage of increased record limits and better performance.

  1. Gradual migration: Start by replacing first with limit in simple queries
  2. Subquery limits: All HasMany relationships now have a default limit of 20. Add an explicit subquery limit to adjust this.
  3. Test thoroughly: Verify that your queries work within the dynamic limits
  4. Monitor performance: Watch for any performance impacts and adjust accordingly

Parameter compatibility

Both parameter types are supported for backward compatibility:

  • The first parameter (deprecated) continues to work with a fixed 200-record limit
  • Queries without either limit or first parameters use the fixed 200-record limit (same as first parameter behavior)
  • Only queries with a top-level limit parameter use dynamic complexity-based limits

This ensures that existing integrations continue to work without modification while allowing new development to take advantage of the increased limits and dynamic protection.