Resource monitor
How memory, cgroup limits, and CPU load are measured.
Concurrency limit
How many runs can execute at once on your host.
Execution queue
How extra runs wait, and when they are rejected.
Tuning
Environment variables and recommended settings.
How it fits together
Every execution request passes through a single gate before a browser is launched:- The gate checks the latest resource snapshot. If the host is not under pressure and fewer runs are active than the concurrency limit, the run starts immediately.
- Otherwise, the run joins the end of a first-in, first-out (FIFO) queue.
- When a run finishes, or the monitor sees resources change, Figranium takes a fresh snapshot and starts queued runs in order until the limit is reached or pressure returns.
- If the queue is full, or a run waits too long, the request is rejected with
503 RESOURCE_CAPACITY_EXCEEDED. - Once running, a non-headful execution is stopped if it exceeds the execution timeout and returns
504 EXECUTION_TIMEOUT.
What goes through the gate
Scheduled runs share the same queue as API and editor runs. If a scheduled run is rejected because capacity is exceeded, it is recorded as a failed execution in the history and the schedule continues to its next run.
Rate limiting is applied before the gate. A request that exceeds
DATA_RATE_LIMIT_MAX is rejected with 429 without entering the queue. See Configuration.Resource monitor
The resource monitor starts when the server boots and samples the host everyRESOURCE_PROBE_INTERVAL_MS (30 seconds by default). Figranium also takes a fresh sample every time a run finishes.
Each sample records:
Container-aware memory
In Docker and other container runtimes, the host’s total memory is misleading: a container limited to 2 GB on a 64 GB server should behave like a 2 GB machine. Figranium reads Linux cgroup memory limits directly, supporting both cgroup v1 and v2. It walks from the process’s own cgroup up to the root and uses the smallest limit it finds. This covers nested cgroups and limits changed at runtime withdocker update --memory. If no limit is set, the host values are used.
Memory reserve
Figranium keeps a memory reserve free for the operating system, the Node.js server, and the database. The reserve is the larger of:RESOURCE_MEMORY_RESERVE_MB(default512)- 15% of total memory
Pressure
The host is considered under pressure ("Busy") when either condition is true:
- Available memory is below the reserve.
- CPU load is at or above
RESOURCE_CPU_THRESHOLD(default0.9).
"Normal". While the host is under pressure, no new runs start, even if there are free slots. Runs already in progress continue. New requests go to the queue.
Pressure counts all memory use on the host or container, not just Figranium’s browsers. Another process using a lot of memory can pause the queue.
On Windows hosts, Node.js does not report a load average, so CPU load is always
0 and only the memory check applies.Automatic concurrency limit
The concurrency limit is the maximum number of executions that can run at the same time. Figranium derives it from total memory and CPU count:
The 768 MB figure is the memory budgeted for each Chromium execution. The limit is never lower than 1 and never higher than 4 unless you set it yourself.
Examples
Overriding the limit
SetMAX_CONCURRENT_EXECUTIONS to a positive integer to replace the automatic limit. Pressure checks still apply: the queue pauses when memory or CPU is under pressure, even below your limit.
.env
Execution queue
Runs that cannot start immediately wait in a FIFO queue. They start in the order they arrived.When queued runs start
Figranium tries to start queued runs:- When a run finishes. A fresh resource sample is taken first.
- When the monitor sees a change. On each probe, if available memory or total memory changed by 128 MB or more, CPU load changed, or the container limit changed, the queue is checked again.
Queue limits
HTTP behavior while queued
A queued API request keeps its HTTP connection open until the run starts and finishes. From the caller’s point of view, a queued request is simply a slow request. The worst case is the queue timeout plus the execution timeout (25 minutes with the defaults).Rejection response
When the queue is full or a run times out in the queue, Figranium responds with:Retry-After (in seconds) and retryAfterMs are both set to the queue timeout. Treat them as an upper bound: capacity often frees up sooner. For retry logic, use exponential backoff capped at the Retry-After value, or poll GET /api/health and retry when queued drops below maxQueue.
Shutdown
When the server shuts down, every waiting run is rejected withRESOURCE_CAPACITY_EXCEEDED so callers are not left hanging. The queue lives in memory and does not survive a restart; callers must resubmit.
Execution timeout
Once a run starts,EXECUTION_TIMEOUT_MS (default 900000, 15 minutes) limits how long it can run. When the timeout is reached, Figranium asks the runner to stop and responds with:
504. The run’s slot is released so the next queued run can start.
Headful runs have no execution timeout, because they are interactive sessions you control. They still take a concurrency slot while active.
Memory safeguards for results
Large results are also bounded so that a single run cannot exhaust server memory:- Extraction workers have bounded output and heap size. An oversized extraction fails for that run only.
- Execution history records are capped at 256 KB each (
MAX_PERSISTED_EXECUTION_BYTES). Larger results are stored with the HTML and data replaced by a truncation notice and only the first 20 log lines kept. See Execution Logs. - Retention deletes captures, recordings, and execution history older than the configured period (7 days by default). See Automatic Retention.
Monitoring
GET /api/health includes a protection object with the current state. It does not require authentication, so you can use it from load balancers and uptime monitors.
The same object is returned by
GET /api/settings/system. See REST API.
What to watch
pressurestays"Busy": the host is short on memory or CPU. CheckavailableMbagainstreserveMbandcpuLoadagainst your threshold.queuedgrows steadily: runs arrive faster than they finish. Add capacity, spread out schedules, or shorten tasks.activeis belowmaxConcurrentwhilequeuedis above 0: the queue is paused by pressure, not by the limit.
Tuning for your deployment
Small VPS or 2 GB container
Small VPS or 2 GB container
Keep the defaults. Figranium runs one execution at a time and queues the rest. If you use video recording or visit heavy pages, raise the reserve so the queue pauses earlier:
.env
Bursty schedules (many tasks at the same minute)
Bursty schedules (many tasks at the same minute)
Allow a deeper queue and longer waits so bursts are absorbed instead of rejected:Staggering cron times by a few minutes is usually more effective.
.env
Large dedicated server
Large dedicated server
The automatic limit tops out at 4. On a machine with plenty of memory and cores, set a higher limit and let the pressure checks guard against overload:
.env
Long-running tasks
Long-running tasks
Raise the execution timeout for tasks that crawl many pages or wait for slow downloads:
.env
The local CAPTCHA model tier is also chosen from memory, but only once at startup. After resizing a host or container, restart Figranium to re-detect CAPTCHA capacity. See CAPTCHA Solving.
Related pages
Configuration
All execution environment variables.
Host Specifications
Recommended hardware for your workload.
Performance
Make tasks faster and lighter.
Troubleshooting
Fix capacity and timeout errors.