---
title: QueueResource Technical Reference
slug: queueresource-technical-reference
createdAt: 2026-06-09T03:09:42.507Z
---

## Overview

QueueResource is the Activate resource type used to queue, retry, suspend, resume, and throttle work that should not fail immediately when a downstream dependency is unavailable, busy, or rate-limited.

Unlike a simple rate limiter, a QueueResource provides a complete queue-backed workflow replay mechanism. It allows workflows to pause safely, be retried later by the Orchestrator, and resume from the point at which they were suspended.

Typical use cases include:

- Service desk integrations
- REST API integrations
- Vendor platforms with rate limits
- Systems that experience transient outages
- Long-running synchronisation processes
- Workflows that should retry automatically rather than fail immediately

## How QueueResource Works

A QueueResource owns an ActivateBackgroundQueue.

Internally, the queue is created or retrieved using:

:::BlockQuote
ProvisioningBackgroundThreads.Instance.GetOrStart(...)
:::

The queue is keyed by the resource path, ensuring that each queue resource maintains its own independent workload.

The queue is responsible for:

- Maintaining queued jobs
- Retrying failed work
- Suspending workflows
- Resuming workflows later
- Applying rate limits
- Tracking queue depth
- Processing retry schedules

At a high level:

:::BlockQuote
Workflow
&#x20;   |
&#x20;   v
QueueResource
&#x20;   |
&#x20;   +--> Queue.ShouldTry
&#x20;   |
&#x20;   +--> Limiter.TryAcquire()
&#x20;   |
&#x20;   +--> External System
:::

## Why Use QueueResource?

A QueueResource allows Activate to:

- Prevent external systems from being overwhelmed
- Retry transient failures automatically
- Suspend workflows safely
- Resume processing later through the Job Service
- Maintain visible queue depth
- Handle vendor outages without generating immediate workflow failures
- Apply rate limits consistently across integrations

## Resource Structure

A QueueResource is configured as a resource node within Activate.

A common pattern is:

:::BlockQuote
Queues
&#x20;├─ ServiceNow
&#x20;├─ Jira
&#x20;├─ Freshservice
&#x20;└─ VendorAPI
:::

The parent queue resource typically contains shared defaults while child queue resources represent individual integration queues.

| Parameter             | Example                           | Purpose                                                                    |
| --------------------- | --------------------------------- | -------------------------------------------------------------------------- |
| Class                 | Innovation.Activate.QueueResource | Defines the resource as a QueueResource                                    |
| Queue\_RetrySequence  | 1,1,1,1,1,5                       | Retry timing sequence                                                      |
| Queue\_SubmitDelay    | 1000                              | Delay between queue submissions (ms)                                       |
| TransactionLimit      | 100/min                           | Queue rate limit                                                           |
| Queue\_Count          | 0                                 | Current queue depth                                                        |
| Queue\_MaxAge         | 1 day                             | Maximum queue item age                                                     |
| Queue\_Timeout        | 10 minutes                        | Idle queue thread timeout                                                  |
| TransactionsPerSecond | 2.0                               | Present in some configurations; verify provider usage before relying on it |

## Queue Creation and Startup

When a queue is first required, GetQueue() requests a queue instance from the background thread manager.

If one does not already exist:

:::BlockQuote
ProvisioningBackgroundThreads.Instance.GetOrStart(...)
:::

creates a new ActivateBackgroundQueue.

TryGetQueue() performs the same lookup without creating a new queue.

## Queue Initialisation

When a queue starts, Activate loads any queued jobs that were previously persisted:

:::BlockQuote
JobCollection.LoadQueuedJobs(this)
:::

Each loaded job ID is added back into the queue.

This allows queued work to survive:

- Orchestrator restarts
- IIS recycles
- Server reboots
- Service interruptions

This process is commonly referred to as queue rehydration.

## Queue Count

Queue\_Count represents the current queue depth.

When the Orchestrator is running:

- Queue count comes from the active background queue

When the Orchestrator is not running:

- Queue count falls back to the stored Queue\_Count parameter

The background queue updates this value automatically.

### Important

Queue\_Count is operational state, not deployment configuration.

Do not manually configure it.

# Understanding ShouldTry

ShouldTry is the primary gate used before calling external systems.

This behaviour is often misunderstood.

Internally, the logic behaves approximately as follows:

:::BlockQuote
if current job is already in this queue
&#x20;   allow processing
else
&#x20;   only allow processing if queue count is zero
:::

### Why?

This prevents new work from bypassing jobs that are already waiting in the queue.

A queued retry should always get the next opportunity to run before new work is introduced.

### Key Concept

QueueResource does not simply rate-limit requests.

New jobs are blocked while work is already queued, but jobs already inside the queue are allowed to continue retrying.

This ensures:

- Fair processing order
- Consistent retry behaviour
- No queue starvation
- No bypassing queued work

## Example Integration Pattern

A typical service desk integration follows this pattern:

:::BlockQuote
QueueResource queue =
&#x20;   Evaluator.GetObject("=//Resources/Integration/Queues/Example")
&#x20;   as QueueResource;

if (queue.ShouldTry)
\{
&#x20;   if (CreateIncident(...))
&#x20;   \{
&#x20;       return JobWorkFlow\.Result.NextStep;
&#x20;   }
}

return JobWorkFlow\.Result.Retry;
:::

Design principles:

- Resolve the queue from the resource tree
- Check ShouldTry immediately before submission
- Submit work only when allowed
- Retry when the queue is busy
- Separate retryable failures from permanent failures

This pattern is widely used in service desk integrations.

# QueueJob()

QueueJob(job) is used when a workflow explicitly needs to move into the retry queue.

The method:

1. Checks whether the job is already queued
2. Prevents duplicate queue entries
3. Adds the job ID to the queue
4. Suspends the workflow
5. Moves the job into WaitingAction
6. Allows the queue to resume it later

The practical effect is:

:::BlockQuote
Running Job
&#x20;     |
&#x20;     v
&#x20;QueueJob()
&#x20;     |
&#x20;     v
WaitingAction
&#x20;     |
&#x20;     v
Background Queue
&#x20;     |
&#x20;     v
Resume Workflow Later
:::

# Background Processing

When a queued job is processed:

:::BlockQuote
BackgroundProcess(jobID)
:::

Activate:

1. Refreshes organisation context
2. Sets the current context name
3. Loads the job
4. Marks the session as queue-driven
5. Creates a JobWorkflow
6. Runs the workflow
7. Continues until completion or waiting state

If the workflow returns:

:::BlockQuote
WaitAction
:::

the queue logs the retry and processes it again later.

If an exception occurs:

- The queue logs the failure
- Attempts to mark the job as failed
- Prevents the queue thread from terminating

# Rate Limiting

QueueResource includes a limiter used to control outbound throughput.

Connectors typically use:

:::BlockQuote
if (!Queue.Limiter.TryAcquire().Succeed)
\{
&#x20;   response.IsRetryable = true;
&#x20;   response.ShouldRetry = true;
&#x20;   return response;
}
:::

This prevents requests from exceeding the queue's configured transaction rate.

The limiter is configured primarily through:

:::BlockQuote
TransactionLimit
:::

If no limit is configured, the current implementation defaults to approximately:

:::BlockQuote
10 transactions per second
:::

# Understanding Burst Capacity

Rate limiting controls long-term throughput.

Burst capacity controls short-term spikes.

Think of it as a bucket:

:::BlockQuote
Capacity builds up while idle
:::

When requests arrive:

:::BlockQuote
Capacity is consumed
:::

When the burst is exhausted:

:::BlockQuote
Requests fall back to the steady rate
:::

For example:

:::BlockQuote
TransactionLimit = 5/sec
Burst = 20
:::

After a quiet period:

:::BlockQuote
20 requests
:::

might be allowed immediately.

After the burst is consumed:

:::BlockQuote
5 requests per second
:::

becomes the sustained processing rate.

This allows:

- Fast processing after idle periods
- Protection against sustained overload
- Better throughput during provisioning spikes

Burst capacity is not unlimited parallelism.

It simply allows temporary acceleration before returning to the configured rate.

# Retry Timing

Retry timing is controlled by:

:::BlockQuote
Queue\_RetrySequence
:::

Example:

:::BlockQuote
1,1,1,1,1,5
:::

The sequence is interpreted as:

:::BlockQuote
Retry 1 after 1 second
Retry 2 after 1 second
Retry 3 after 1 second
Retry 4 after 1 second
Retry 5 after 1 second
Retry 6 and onwards after 5 seconds
:::

Rules:

- Comma or semicolon separated
- Values are seconds
- Empty sequence defaults to one minute
- Final value repeats indefinitely

This allows aggressive retrying for short-lived failures while backing off for longer outages.

# Queue Processing Parameters

| Parameter            | Purpose                         |
| -------------------- | ------------------------------- |
| Queue\_RetrySequence | Retry timing sequence           |
| Queue\_SubmitDelay   | Delay between queue submissions |
| Queue\_MaxAge        | Maximum age of queue entries    |
| Queue\_Timeout       | Idle thread timeout             |
| Queue\_Count         | Current queue depth             |
| TransactionLimit     | Rate limiting configuration     |

# Connector Pattern

For API connectors, the recommended pattern is:

:::BlockQuote
if (Queue != null && !Queue.ShouldTry)
\{
&#x20;   return RetryResult();
}

if (Queue != null && !Queue.Limiter.TryAcquire().Succeed)
\{
&#x20;   return RetryResult();
}

SendRequest();
:::

This ensures:

- Queue ordering is respected
- Rate limits are enforced
- Busy systems are protected
- Retries are handled consistently

# Operational Guidance

## Keep Queues Specific

Use one queue per external system.

Good:

:::BlockQuote
Queues
&#x20;├─ ServiceNow
&#x20;├─ Jira
&#x20;├─ Workday
:::

Avoid:

:::BlockQuote
Queues
&#x20;└─ SharedExternalSystems
:::

unless a shared throttle is intentional.

## Treat Queue\_Count as State

Queue\_Count should never be treated as deployment configuration.

It is runtime state maintained by the queue.

## Tune Retry Timing Carefully

Example:

:::BlockQuote
1,1,1,1,1,5
:::

is aggressive.

Useful for:

- Short locks
- Temporary API delays

Less useful for:

- Vendor outages
- Extended maintenance windows

For unstable APIs, use longer retry intervals.

## Monitor Queue Logs

Queue logs show:

- Queue startup
- Submission attempts
- Retry processing
- Queue depth changes
- Limiter statistics

These logs are often the fastest way to diagnose queue issues.

# Troubleshooting

| Symptom                      | What to Check                                             |
| ---------------------------- | --------------------------------------------------------- |
| Jobs are not retrying        | Confirm the Orchestrator is running                       |
| Queue count remains non-zero | Review pending jobs for the queue                         |
| Jobs retry too quickly       | Increase Queue\_RetrySequence                             |
| Jobs retry forever           | Check workflow return values                              |
| External API overloaded      | Lower TransactionLimit                                    |
| Duplicate submissions        | Ensure ShouldTry is checked immediately before submission |

# Summary

QueueResource is Activate's queue-backed retry, replay, suspension, and throttling mechanism.

It allows workflows to:

- Pause safely
- Retry automatically
- Resume later
- Respect external rate limits
- Avoid overwhelming downstream systems

The typical pattern is:

1. Define a QueueResource
2. Configure retry and rate-limiting settings
3. Resolve the queue in code
4. Check ShouldTry
5. Optionally acquire limiter capacity
6. Call the external system
7. Retry or queue work when necessary
8. Allow the Orchestrator to replay the workflow later

This makes QueueResource the preferred mechanism for service desk integrations, vendor APIs, and any workflow where temporary failure should not immediately become job failure.
