Download Reportworq
⬇ Guide PDF

Distribute the load#

This page is about provisioning and placement: deciding how much hardware a workload needs, and making sure the work actually spreads across it. It answers the question customers ask most often, which is some version of "how many servers do we need, and why did adding one not help as much as we expected".

When to use it. Before a new deployment, before a close window you expect to be tight, when adding nodes to an existing cluster, and whenever throughput is not scaling the way the server count suggests it should.

Before you start#

Size the server before you size the settings#

Two settings on Settings ▸ Configuration ▸ Performance, under Execution, set how much a server takes on at once.

Setting Default Range What it limits
Parallel Job Execution 4 1 to 50 Server-level concurrency: how many top-level jobs run at once
Tasks per Job 3 1 to 50 Per-job concurrency: how many outputs or variations run at once inside one job

Two different controls share the name "Parallel Job Execution". On Settings ▸ Configuration ▸ Performance ▸ Execution it is the server's own top-level job concurrency, and it accepts 1 to 50. On a load-balancer node's own settings screen, and as the max-jobs spinner on the main server's Load Balancer grid, it is that node's routing capacity, and it accepts 0 to 128. They are stored separately and do different work. Check which screen you are on before you change one.

Their product is the theoretical maximum number of concurrent tasks. At the defaults that is 12; at 5 by 5 it is 25.

The rule that governs the whole page: peak memory scales with the number of jobs in flight. Allow roughly 2 GB per concurrent job on top of the base footprint, so five parallel jobs want about 10 GB free at the peak. Size these settings against the RAM the server actually has, not against its core count. A server tuned past its memory does not degrade gently: it runs out of memory under load.

Size against your peak concurrency rather than your average. The busiest ten minutes of the close is what the machine has to hold.

On Azure, the same arithmetic picks the plan. A B2 plan is enough for a proof of concept or a pilot; production wants P1v3 or above for the RAM and throughput a real job load needs. Run exactly one web instance, which owns the UI and the scheduler, and add worker nodes against the same shared repository for throughput. See Deployment topology.

What a cluster distributes, and what it does not#

When one server cannot finish the load inside its window, scale out into a load-balanced cluster. Getting value from it depends on knowing exactly what it spreads.

It distributes whole jobs, and a job is atomic. Each job runs start to finish on a single node. A node that is not allowed to run a queued job re-queues it so another node picks it up. This is how batch job execution, Excel reporting, and campaign form load spread across the cluster.

It does not distribute interactive Excel add-in refresh. When an analyst refreshes a Data Model view or a Direct Query in the add-in task pane, that query runs on whichever node holds their session, whatever the load balancer's capacity settings say. Distributing interactive refresh is planned for a later phase. Today, plan interactive analyst load against the node people sign in to, not against the cluster total.

Contribution session placement has its own rule. When a contributor opens a form, Reportworq checks every online server and steers the new session to the one with the most available memory that can still accept a session. That is a separate mechanism from job routing, and it is governed by the 90% memory admission valve rather than by node capacity settings. See Scale and size a contribution campaign.

Design jobs so the cluster can spread them#

This is the answer to "we added a node and throughput barely moved", and it is a job-authoring decision rather than a settings one.

Because a job runs atomically on one node, a single job can never use more than one node's capacity, no matter how many nodes you own. The two levers are therefore different in kind:

So, when a batch is not spreading:

  1. Count the jobs, not the outputs. A close batch expressed as one enormous job pins itself to one machine. The same work expressed as one job per region, entity, or pack is what lets the cluster work.
  2. Check Tasks per Job against the shape of each job. A bursting job producing forty outputs on a node whose Tasks per Job is 3 is running three at a time on purpose.
  3. Remember both limits are per server. Each server runs up to its own Parallel Job Execution and its own Tasks per Job, so cluster capacity is the per-server figure multiplied by the server count. Grow throughput by adding nodes rather than by pushing one server's limits past what its RAM can hold.

One more shape worth knowing. An instance with several workspaces shares one job queue across all of them. Rows belonging to other workspaces are redacted and cannot be expanded or canceled until you switch to that workspace. So one workspace's batch is not isolated from another's by the workspace boundary, and a heavy tenant can occupy queue capacity that another workspace is waiting on. Plan the clock across the whole instance, not per workspace.

Set per-node capacity#

A load-balancer node presents a reduced shell at its own address, with an Execution category carrying:

These are the same three values as the node's row on the main server's Settings ▸ Load Balancer grid, where they appear as the node name, the enable switch, and the max-jobs capacity spinner. Edit them from either end.

Size capacity against the machine, not against the cluster. A node's max-jobs value should not exceed what its RAM can actually hold, because peak memory scales with jobs in flight and the routing limit knows nothing about how much memory the machine has.

Concentrating execution on dedicated nodes. A node's Parallel Job Execution accepts 0, and its Enable Execution checkbox can be cleared, so a node can stay registered in the cluster and take no work. That is how you drain a node ahead of maintenance without removing it and having it re-register.

The main server's own Parallel Job Execution, on Settings ▸ Configuration ▸ Performance, is the other control described above and accepts 1 to 50; it cannot be set to 0. So the main server always keeps some execution capacity of its own. To concentrate batch work on dedicated nodes, lower the main server's value and raise the nodes', rather than trying to zero the main server. Given that interactive add-in refresh is not distributed and lands on the node holding the session, leaving the main server a small amount of capacity while the nodes carry the batch is usually the split you want anyway.

Taking a node out of service. Disable it, or lower its max-jobs, before patching its host, so no new jobs route to it. Remove deletes the entry but a still-running server re-registers itself and reappears; stop its service to retire it for good.

Pin work to specific nodes with Filter jobs#

The per-node Filter jobs action opens a tri-state tree (include, exclude, or inherit) over the instance's workspaces, folders, and jobs, with two modes: Include all jobs and workspaces, which is the default, or Include or exclude specified jobs and workspaces.

Reportworq saves the filter on the node and enforces it when routing. For each queued job it checks the job, then walks up its parent folders, then its workspace, and re-queues any job the node is not allowed to run so another node picks it up.

Filters are a placement tool, not a throttle. Three uses earn their keep:

The trap. Every exclusion narrows the pool of nodes eligible for that job. Exclude a job everywhere and it never runs. Filters are worth auditing after node changes, because a filter written against a three-node cluster can quietly strand work when a node is removed.

Spread the clock#

Capacity is not only how much hardware you own; it is how much of it is idle at 07:59 and oversubscribed at 08:00. Two facts make this concrete.

The 30-minute overdue rule. When the scheduler cannot run an occurrence at its due time, because the master scheduler was paused, the host was down, or a prior run of that schedule was still going, the occurrence becomes overdue. An occurrence more than 30 minutes overdue is skipped, not run late. This is a fixed rule and not a setting.

That last cause is the capacity-planning one. A schedule whose runs regularly take longer than its interval will start missing occurrences, and past 30 minutes they are silently skipped rather than queued. The symptom looks like missing output rather than slow output, which is why it is worth checking the schedule shape before checking the server. To force a skipped run, use Run now on that schedule's row.

Everything at the top of the hour is a spike everywhere. A single clock time concentrates job execution, source system load, and outbound mail into one moment. Stagger schedules across the window you actually have rather than across the minute you happen to have picked, and give the heaviest jobs the start of the window rather than the end of it.

Schedule health, the overdue footer, and the failure counts are on Scheduled Content. See Manage scheduled content.

Keep the tiers out of each other's way#

Three isolation settings decide whether one kind of work can hurt another. All three ship on, and the useful thing is knowing what each protects.

Setting Where What it protects
Enable Out of Process Job Execution Settings ▸ Configuration ▸ Performance Runs job execution outside the web app process and frees its memory after each run, so a heavy job cannot pressure the web tier. Leave on unless support advises otherwise.
Enable Out of Process Reporting Queries Settings ▸ Configuration ▸ Performance ▸ Reporting Runs an analyst's interactive add-in query in a dedicated worker rather than inline on their web session, so a runaway query cannot stall other users or exhaust the web app.
Enable Out of Process Contribution Sessions Settings ▸ Configuration ▸ Performance ▸ Contribution Runs form calculation in separate worker processes, which is what makes the per-server memory console and the admission valve possible.

Two behaviors of the reporting worker are worth knowing before you rely on it:

The Reporting category carries three more settings beside the toggle.

Setting Default What it does
Reporting Log Level Warning The log level passed to the reporting worker.
Worker Start Timeout 90 seconds How long to wait for a spawned worker to load its plugins and connect before failing the query. The worker hosts the full connector stack, so its cold start is heavier than a contribution worker's.
Query Timeout 300 seconds How long to wait for a single query to return. This is a ceiling on how long one query may occupy a worker, so raise it only for a genuinely long query you intend to support.

The idle threshold that retires a quiet worker is 30 minutes and has no control on this screen; it is a settings-file value.

Housekeeping that protects capacity#

These do not make a job faster, but they stop an instance getting slower over months.

Lever Where Why it matters
Default History Retention (30 days) Settings ▸ Configuration ▸ Performance ▸ Execution Bounds how much run history and stored output accumulates. Per-folder and per-report policies, and pinning, are on Output retention.
Compress History Files (on) Settings ▸ Configuration ▸ Performance ▸ Execution Compresses job-history databases at rest. Performance measurements honor it too.
Log Retention (90 days) and Audit retention (90 days) Settings ▸ Configuration ▸ Logging Logs and audit files grow with activity. A value of 0 on audit retention keeps them indefinitely, which is a deliberate choice rather than a default to leave unexamined.
Enable Debug Logging (off) Settings ▸ Configuration ▸ Logging A live instance-wide switch that produces very large logs and HTTP-Archive files. It sits outside the save flow and takes effect immediately. Turn it on only when support asks, and off again after the capture. Leaving it on is a real and avoidable drag.
Recycle Service (off) Settings ▸ Configuration ▸ Web Server An automatic daily restart at a chosen time to free resources. Users refresh their browsers afterwards, so pick an hour nobody is working.
Clear Repository Cache Settings ▸ Configuration ▸ Performance, under Advanced Features An advanced action in a category that is collapsed by default. Use it when support asks rather than as routine maintenance.

Retention is also what bounds your diagnostic history. Performance measurements are stored with the run and go when the run goes, so a 30-day retention gives you a 30-day comparison window. If you compare period-close runs year on year, pin them.

A provisioning sequence that works#

  1. Estimate from the baseline. Start at 32 GB plus roughly 2 GB per concurrent job, and decide the peak concurrency the window requires. See System requirements.
  2. Set concurrency to what the RAM supports, not to the core count, using Parallel Job Execution and Tasks per Job.
  3. Run a representative batch and measure it. The Performance tab reports each run's peak memory and maximum CPU, and Settings ▸ Performance ▸ Distribution reports the median run across the estate. That is your real per-job cost, replacing the 2 GB rule of thumb.
  4. Check the shape of the work before adding hardware. If throughput is not scaling with nodes, count the jobs, because a monolithic job cannot use a second machine.
  5. Add nodes, then size each one. Open ports 8600 and 8601 on every server, put the Repository on a UNC share every node can reach, set Web App Host on the main server before starting any node, and run the same version everywhere. See Deployment topology.
  6. Place the work. Set per-node max-jobs and Parallel Job Execution, consider the coordinator pattern, and use Filter jobs where a job belongs on particular nodes.
  7. Spread the clock, and confirm no schedule is regularly overrunning its own interval.
  8. Size contribution separately if the deployment collects input. See Scale and size a contribution campaign.
  9. Re-measure after the first real close and adjust. The first estimate is an estimate; the second one is evidence.

Notes and limits#

Going deeper. For diagnosing content that is already slow, see Manage and improve performance. For the cluster mechanics, node join, and cloud shapes, see Deployment topology. For every setting named here, see Server configuration. For contribution sizing arithmetic, see Scale and size a contribution campaign.

Feedback on this page

Comments, questions, requests, or something missing or unclear? Email us - the page you are on is filled in for you.

Email feedback on this page

Or write to support@reportworq.com directly.