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#
- You need the Administrator entitlement. Every setting on this page is under Settings, which is administrator-only, and the Performance page is not offered on a load-balancer node.
- Read Performance and capacity planning first if you have not. In particular, distribution and contribution are sized separately, and this page is mostly about distribution.
- Have the baseline requirements to hand: System requirements.
- Scaling out to more than one server needs a Load Balancer node count of 1 or more on your license. See Licensing and entitlements.
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:
- Split the work into more jobs to use more nodes. Ten jobs can occupy ten nodes. One job cannot.
- Raise Tasks per Job to use more of one node. Within a single job, its outputs and variations run in parallel up to that limit, on the node that owns the job.
So, when a batch is not spreading:
- 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.
- 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.
- 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:
- A Server Instance Name, which identifies it in job screens, the Load Balancer monitor, and the node pivot on Settings ▸ Performance ▸ Distribution. Set something meaningful here: it is the label every later diagnosis reads.
- An Enable Execution checkbox, which is what decides whether the node takes work at all.
- A Parallel Job Execution value from 0 to 128, which caps how many jobs route to that node.
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:
- Keep a long job off the fast lane. Exclude a single multi-hour job from the nodes that serve short interactive-feeling runs, so it cannot occupy their slots.
- Match a job to a node that can reach its data. A job whose source workbooks live on a network folder only some nodes can reach belongs on those nodes. This is a correctness problem before it is a performance one, and the filter is where you express it.
- Reserve a node for one workspace or one folder. Useful where one team's close cannot be allowed to queue behind another's.
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:
- It is retired when idle and respawns on demand. A worker that has been idle past its threshold is shut down so its warm connections and caches are released; the next query for that workspace transparently starts a fresh one. A cold start is therefore normal after a quiet period rather than a fault.
- If the worker cannot start, Reportworq falls back to running the query in the web app. The failure is written to the host log and the fallback holds for five minutes before another attempt, so a host problem does not leave analysts staring at a spinner. The toggle continues to read as enabled while this is happening, so the host log is where you confirm it, not the settings screen. A clean start clears the fallback immediately, so a fixed host goes straight back out of process.
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#
- 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.
- Set concurrency to what the RAM supports, not to the core count, using Parallel Job Execution and Tasks per Job.
- 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.
- 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.
- 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.
- 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.
- Spread the clock, and confirm no schedule is regularly overrunning its own interval.
- Size contribution separately if the deployment collects input. See Scale and size a contribution campaign.
- Re-measure after the first real close and adjust. The first estimate is an estimate; the second one is evidence.
Notes and limits#
- Concurrency limits are per node. Cluster capacity is the per-node figure multiplied by the node count, and there is no instance-wide concurrency ceiling to set in one place.
- A job never spans nodes. No setting changes this. Job granularity is the lever.
- Interactive add-in refresh is not distributed across the cluster and lands on the node holding the analyst's session.
- Load balancing is licensed as a node count; 0 disables it, and a single-node install shows an empty node grid.
- A node's Status reflects a successful job-dequeue attempt in the last two minutes, so it reports participation rather than health.
- The 30-minute overdue window is fixed and cannot be configured.
- There is no throttling by priority. Reportworq has no job priority or queue-weighting control. Placement is expressed through node capacity, filters, and the clock.
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 pageOr write to support@reportworq.com directly.