Repository navigation
Queue Share and Speed Limits
Applies to Hydranos 4.4.
For anyone who wants to cap how many torrents run at once, stop or remove seeds after a ratio or a seeding time, or limit upload and download speed. You will learn which key does what, where to set it (web UI, native API, qBittorrent API), its exact default for race and hoard, and what is still missing in 4.4. Terms: Concepts and Glossary. Engines and roles: Engines: Race and Hoard.
Every setting on this page is per engine: [race], [hoard], or the session of an extra engine block (an extra engine inherits its role's values unless its own session sets them). Except start_paused, every key here is applied live when you change it from the web UI or an API: save it and the next pass of the worker uses it, no restart. A hand edit of default.toml is not: it is read at the next start, or when the next UI or API change rewrites the file (Configuration: Engines).
| Level | Web UI | Native API | qBittorrent API (shim) |
|---|---|---|---|
| Engine (queue, slow torrents, share limits, speed caps, choker) | Config tab › Advanced settings (default.toml) › Session Race / Session Hoard, then Save settings |
POST /api/settings; /api/engines/:id/share-limits; /api/engines/:id/rate-limits
|
app/setPreferences (writes every local engine) |
| One torrent (share limits, speed caps) | right-click › Share limits… / Limit rate… |
/api/torrents/:info_hash/share-limits; /api/torrents/:info_hash/limits; selection actions share_limits, limits (POST /api/selection/:action) |
torrents/setShareLimits; torrents/setUploadLimit, setDownloadLimit; add fields ratioLimit, seedingTimeLimit, inactiveSeedingTimeLimit, upLimit, dlLimit
|
| Whole client (speed cap only) | — | read only (GET /api/engines/:id/rate-limits) |
transfer/setUploadLimit, transfer/setDownloadLimit; setPreferences up_limit / dl_limit
|
The settings editor lists queueing, active_seeds, active_limit, the slow-torrent, share-limit and speed-cap keys and choking even when your default.toml lacks them, at their default value; saving one creates it in [race] or [hoard]. active_downloads and max_uploads_per_torrent appear only if the file already has them (the shipped template has active_downloads in [hoard] only). The editor only covers [race] and [hoard]: for an extra engine, use the native routes (they write into its block) or edit the file.
Each local engine runs a queue manager. Its first pass comes about a minute after the engine starts (a 30-second settle, then the 30-second wait), then one every 30 seconds, reading the limits from the live config on each pass.
| Key | Meaning | Template race | Template hoard | Absent from the file |
|---|---|---|---|---|
active_downloads |
Downloads running at once. Always applies, with or without queueing. |
not set | 10 |
0 = no ceiling |
queueing |
qBittorrent's queue switch: turns on active_seeds and active_limit. |
false |
false |
false |
active_seeds |
Seeds running at once, read only while queueing = true. |
-1 |
-1 |
no ceiling |
active_limit |
Downloads + seeds running at once, read only while queueing = true. |
-1 |
-1 |
no ceiling |
0 or a negative value means "no ceiling" for all three. queueing exists as a guard: 3.x put active_seeds = 50 / active_limit = 100 on race, and a file carrying them would otherwise stop all but 50 seeds at the upgrade. Those two keys do nothing until you set queueing = true.
- A torrent you stopped (Stop, a share limit's stop) is invisible to the queue: it neither takes a slot nor gets started.
- A torrent in error is left out. A torrent being checked holds a download slot.
-
Downloads are ranked by the swarm's seeder count, from the tracker announce cache, most seeders first: the likeliest to finish gets the slot. Inside the ceiling, a waiting one is started; past it, a running one is stopped. It keeps its progress and shows queued (tooltip Waiting for a slot;
queuedDLover the shim) until a slot frees. - The seeder count is the last one a tracker answered to an announce. A queued torrent is stopped, so it does not announce and its count stays where it was when it was stopped; a torrent never announced counts 0. Scrape figures are not used for the ranking. A dead release therefore ranks last and waits until fewer torrents above it need a slot; without the slow rule below, it can wait as long as better-seeded downloads keep arriving.
-
Seeds (only under
queueing) are kept by age, oldest added first. Their ceiling isactive_seeds, and at mostactive_limitminus the downloads now running. A seed past it is stopped and remembered as parked (queuedUPover the shim). The queue only ever restarts seeds it parked itself; lift the ceiling and every parked seed starts again. - Ranking by age rather than by a swarm figure is deliberate: a ranking that moves would stop and start seeds on every pass, and each stop sends a
stoppedannounce.
flowchart TD
P["Queue pass, every 30 s, live config"] --> L{"Any ceiling?<br/>active_downloads > 0, or queueing<br/>with active_seeds / active_limit > 0"}
L -->|no| N["Nothing touched<br/>(seeds it parked earlier start again)"]
L -->|yes| F["Skip: torrents you stopped, torrents in error"]
F --> D["Incomplete torrents (checking included),<br/>most swarm seeders first"]
D --> S1{"dont_count_slow_torrents and this one runs<br/>under its threshold for the timer?"}
S1 -->|yes| K1["Keeps running, holds no slot"]
S1 -->|no| C1{"Under min(active_downloads, active_limit)?"}
C1 -->|yes| R1["Runs: started if waiting"]
C1 -->|no| Q1["Stopped if running: queued"]
R1 --> SE
Q1 --> SE
K1 --> SE
SE{"queueing with active_seeds<br/>or active_limit?"} -->|no| E["End of pass"]
SE -->|yes| D2["Running or parked seeds, oldest added first"]
D2 --> S2{"Slow rule: uploading under<br/>its threshold for the timer?"}
S2 -->|yes| K2["Keeps running, holds no slot"]
S2 -->|no| C2{"Under min(active_seeds,<br/>active_limit minus running downloads)?"}
C2 -->|yes| R2["Runs: a parked seed is started"]
C2 -->|no| Q2["Stopped and parked: queued"]
qBittorrent's "do not count slow torrents in these limits". A running torrent that stays under its threshold for the timer keeps running but no longer counts in active_downloads, active_seeds or active_limit, so the next candidate gets the slot. It works with or without queueing (for active_downloads).
| Key | Meaning | Absent from the file |
|---|---|---|
dont_count_slow_torrents |
The switch. | false |
slow_torrent_dl_rate_threshold |
A download under this rate, in KiB/s, is slow. 0 = never slow. |
2 |
slow_torrent_ul_rate_threshold |
A seed uploading under this rate, in KiB/s, is slow. 0 = never slow. |
2 |
slow_torrent_inactive_timer |
Seconds under the threshold before it stops counting. | 60 |
These four keys are not in the shipped template; the settings editor shows them at the values above (the switch as a toggle, the three figures as number fields; then Save settings). With the rule on, the ceiling caps the fast torrents, not the running ones: a release stuck at 99 % waiting for a seeder stops holding one of your slots, and more torrents than the ceiling can be running at once.
- Only a running download can turn slow, and a stalled one (
stalledDL: running, no data coming) is running: after the timer it frees its slot. A queued torrent is not running, so the rule never applies to it; it gets a slot by its seeder rank only. - The timer restarts whenever the torrent's rate reaches the threshold. A slow torrent that speeds up counts again at the next pass, at its place in the seeder ranking: inside the ceiling it keeps running, and the lowest-ranked running download past the ceiling is stopped (queued); outside it, it is stopped and queued itself.
- Force download / Stop forcing (right-click › State, shown for incomplete hoard torrents) marks the torrent as forced: it appears under the Forced filter chip of the Hoard list. The queue runs a forced torrent past the ceiling and does not count it against the slots: a queued forced torrent is started at the next pass (within 30 s) and is never stopped by the queue. A torrent you stopped yourself stays stopped until you Start it.
- Start on a queued torrent that is not forced starts it, but the next pass (within 30 s) stops it again if it does not rank inside the ceiling. Force download is the way to jump the queue.
- Over the shim,
torrents/setForceStartwithvalue=truedoes what Force download does, on every copy of the torrent, and starts it, a stopped torrent included: it runs past the ceiling of any engine.value=falselifts the mark and leaves the torrent to the queue. Rows always reportforce_start: false. -
torrents/topPrio,bottomPrio,increasePrio,decreasePrioanswer 409:Torrent queueing is not enabledwhen no engine holding the torrents runs a queue,Hydranos orders its queue itself (most seeders first for downloads, oldest first for seeds): positions cannot be set; force start runs a torrent past itwhen one does.
[race]
active_downloads = 5 # live when saved from the UI or an API; no `queueing` needed
dont_count_slow_torrents = true # a stalled release frees its slot
slow_torrent_dl_rate_threshold = 2 # KiB/s
slow_torrent_inactive_timer = 60 # secondsWhat to expect:
- Coming from qBittorrent behind Sonarr/Radarr? Your imported torrents and their grabs are in hoard: put these keys under
[hoard]instead (the template already hasactive_downloadsthere, so Session Hoard shows it). See Migrating from qBittorrent. - Race has no download ceiling by default (hoard has 10). Set it in the file as above (the Session Race editor shows
active_downloadsonly once the file has it), or over the shim (below). Saved from the UI or an API, it applies at the next pass; a hand edit of the file waits for the next start or the next save from the UI. - The 5 that run are the 5 with the most seeders in their swarm, not the 5 added first. The others show queued, with their progress kept.
- A torrent you stopped by hand does not count and is not started.
- With the slow rule, more than 5 can be running: the slow ones keep going without a slot. Leave it off for a hard ceiling of 5.
-
queueingis not needed: it only governsactive_seedsandactive_limit. - Over the shim,
app/setPreferenceswith{"max_active_downloads": 5}does the same, but writesactive_downloadson every local engine, hoard included.app/preferencesshows race's values (max_active_downloads-1 when race has none, the slow-torrent keys at race's or their defaults), andsetPreferenceswritesmax_active_downloadsand each slow-torrent key only when it differs from that: a client that posts back the page it read leaves your[hoard]values alone, but one that sends a new value overwrites them on every engine. - An extra engine takes
active_downloadsfrom its own session, or from its role's section if it does not set one.
qBittorrent's share limits: when a seed reaches any of its limits (each tested with >=), the engine's action is applied.
| Key | Meaning | Template race and hoard | Absent from the file |
|---|---|---|---|
max_ratio |
Ratio limit (float). | -1.0 |
off |
max_seeding_time |
Minutes of seeding. | -1 |
off |
max_inactive_seeding_time |
Minutes with nothing uploaded. | -1 |
off |
share_limit_action |
"stop", "remove" (files stay) or "remove_with_files". |
"stop" |
stop |
A negative value switches a limit off. "pause" and "" read as stop, and so does a value the daemon cannot read. The ratio is uploaded ÷ downloaded (lifetime counters); when downloaded is under 1 % of the data held (a seed-mode add or a cross-seed), it is uploaded ÷ data held, as in qBittorrent.
A limit never acts before the seed has served its tracker's Minimum seed (announce_min_seed_hours, declared per tracker host on the Trackers tab), the same test the race drain uses (Race Drain and Graduation). This holds for every action, stop included.
-
A tracker with nothing declared holds the limit: the seed keeps seeding, whatever the limit says. To let limits act on a tracker's torrents, declare its hours,
0included. - A torrent with no tracker owes nothing: the action applies.
- The tracker tested is the torrent's first live tracker.
- A held seed is logged once, not every pass: share limit reached, held: the tracker declares no minimum seeding time … or … the tracker's minimum seeding time is not served yet.
flowchart TD
A["Share-limit pass: 90 s after start,<br/>then every 120 s, per local engine"] --> B{"Seeding, or stopped by the queue<br/>with all its data?"}
B -->|"no: downloading, checking,<br/>error, stopped by you"| X["Not touched"]
B -->|yes| C{"Ratio, seeding time or inactive time<br/>at or over its limit (torrent's own, else engine's)?"}
C -->|no| X
C -->|yes| D{"Tracker's Minimum seed declared<br/>and served? (no tracker: yes)"}
D -->|no| H["Held: keeps seeding, logged once"]
D -->|yes| M{"500 actions already this pass?"}
M -->|yes| NX["Left for the next pass"]
M -->|no| ACT{"share_limit_action of the engine"}
ACT -->|stop| ST["Stopped as by Stop:<br/>shows stopped, the queue never restarts it"]
ACT -->|remove| RM["Removed from this engine,<br/>trackers hear stopped, files stay"]
ACT -->|remove_with_files| RF["Removed; files deleted<br/>except those another torrent reads"]
- Each local engine has its own worker; at most 500 stops or removals per pass, so a ratio limit turned on over a large library spreads its work: at most 15,000 actions an hour per engine, so 100,000 seeds already over the limit take about 7 hours to be acted on.
- Removal goes through the normal removal path: trackers receive
stopped, and the files are deleted except those another loaded torrent reads at the same path (see Jobs, Bulk Actions and Moving Data). - Seeding time is the torrent's counted seeding time, kept across restarts.
Not implemented in 4.4: the inactivity clock lives in memory — it starts when the worker first sees the seed, so every daemon start grants a full
max_inactive_seeding_timeagain (the editor says "Counted from the daemon's start") — there is no per-torrent action (a torrent's limits always use its engine'sshare_limit_action) and no super seeding.
A torrent can carry its own limits: -2 = follow its engine, -1 = no limit, ≥ 0 = its own limit (times in minutes). They belong to the torrent, so every copy has them; each copy still uses its own engine's action.
- Web UI: right-click › Share limits… opens Share limits: {n} torrent(s) with Ratio limit, Seeding time limit (minutes) and Inactive seeding time limit (minutes), then Apply / Cancel. An empty field keeps the current value. For one torrent the fields start at its current values.
-
Detail panel (race and hoard, General): the Share limits line shows what is in force, e.g.
ratio 2 · seeding 1440 min · inactive none → stop, with(engine)next to a value taken from the engine. -
Native:
GET|POST /api/torrents/:info_hash/share-limits, body{"ratio_limit": 2.0, "seeding_time_limit": 1440, "inactive_seeding_time_limit": -2}(each optional, at least one, else 400). The answer lists, per local copy, the torrent's own values, theeffectiveones and the engine'saction. -
Shim:
torrents/setShareLimitswithhashes(orall),ratioLimitandseedingTimeLimitrequired (400 without them),inactiveSeedingTimeLimitoptional (absent = -2). The same three fields are read ontorrents/add.torrents/infoandpropertiescarryratio_limit,seeding_time_limit,inactive_seeding_time_limit(the torrent's own) andmax_ratio,max_seeding_time,max_inactive_seeding_time(in force).
-
Web UI: Session Race / Session Hoard, keys as above;
share_limit_actionis a drop-down (stop,remove,remove_with_files). -
Native:
GET|POST /api/engines/:id/share-limits, body any ofmax_ratio,max_seeding_time,max_inactive_seeding_time,share_limit_action. Unknown field or bad action → 400, unknown engine → 404. It writes the key into[race],[hoard]or the engine's block (creating it if missing). -
Shim:
app/preferencesshows the limits ofrace(or the first local engine):max_ratio_enabled,max_ratio,max_seeding_time_enabled,max_seeding_time,max_inactive_seeding_time_enabled,max_inactive_seeding_time,max_ratio_act(0 stop, 1 remove, 3 remove with files).app/setPreferencestakes a value only with its*_enabledflag and writes it on every local engine, and only when it differs from what the page shows (a client that posts back the whole page changes nothing).max_ratio_act = 2(super seeding) is logged and leaves the action unchanged.
A share limit and a workflow can do the same job; a workflow is for rules a share limit cannot express (per category, per tracker, tags…).
Three levels, each optional. The client cap is shared by every engine, an engine's cap by all of that engine's torrents together (one cap on their sum, not a per-torrent default), a torrent's cap by that torrent alone. A block of data has to clear all three, so the narrowest one wins:
| Level | Set by | Unit | Kept across restarts |
|---|---|---|---|
| Client (qBittorrent's "global" limit, one for the whole process, above every engine) | shim only: transfer/setUploadLimit, transfer/setDownloadLimit (limit, 400 without it), setPreferences up_limit / dl_limit
|
bytes/s, 0 or negative = none |
yes (store setting client_rate_limits, restored at boot) |
Engine: upload_rate_limit, download_rate_limit
|
Session Race / Session Hoard; POST /api/engines/:id/rate-limits
|
file and editor: bytes/s; native route: KiB/s (upload_kib, download_kib) |
yes (the file) |
| Torrent | right-click › Limit rate…; POST /api/torrents/:info_hash/limits; shim torrents/setUploadLimit, setDownloadLimit; add fields upLimit, dlLimit
|
UI and native: KiB/s (up_kib, down_kib); shim: bytes/s |
yes (the torrent's resume record) |
- Template, race and hoard:
upload_rate_limit = 0,download_rate_limit = 0(unlimited).0or negative = unlimited at every level. - The caps are token buckets on peer traffic, with a burst of a quarter of a second (at least 32 KiB). A change applies at once, without a restart.
-
Limit rate… opens Limit rate: {n} torrent(s) with Upload limit (KiB/s) and Download limit (KiB/s): "This torrent's own cap, in KiB/s. 0 = no cap of its own (the engine's still applies). Leave a field empty to keep its current value." The native route caps every local copy unless
?engine=names one; the shim caps every copy. - The detail panel's Speed limits line reads
↑ X · ↓ Y: per direction the torrent's own cap, or the engine's followed by(engine)when the torrent has none or the engine's is narrower, orunlimited. The client cap is not shown there. -
GET /api/engines/:id/rate-limitsanswers the engine's caps from the file (upload_kib,download_kib), what the engine holds now (upload_limit,download_limit, bytes/s) and the client cap (client_upload_limit,client_download_limit). - Over the shim,
transfer/infoandsync/maindatareportup_rate_limit/dl_rate_limit= the client cap;torrents/uploadLimit/downloadLimitanswer0for none,torrents/infosays-1.
Not implemented in 4.4: the client-wide cap can only be set over the qBittorrent API — no web UI control and no native route writes it — and there are no alternative or scheduled speed limits (
toggleSpeedLimitsModedoes not exist).
Off by default, and best left off. With choking = true, each seeding torrent serves only max_uploads_per_torrent interested peers at a time, re-ranked every 10 seconds by 0.7 × rarity + 0.3 × speed (rarity = share of the torrent the peer still lacks; speed = what it took in the last 10 s, relative to the fastest). Downloading torrents are not choked. Switched off while running, it unchokes every peer it had choked.
| Key | Template race | Template hoard | Absent from the file |
|---|---|---|---|
choking |
false |
false |
false |
max_uploads_per_torrent |
100 |
-1 |
0 = 4 slots |
max_uploads_per_torrent is read only while choking = true; negative = unlimited. Both are live. The template warns why it is off: on a large library it churns the peers and can cut total upload by an order of magnitude; turn it on only when your uplink itself is the bottleneck. The shim's app/preferences shows race's max_uploads_per_torrent; setPreferences does not write it.
[race.custom_choking] from 3.x is still ignored; the daemon names it in a startup warning that points to choking = true and max_uploads_per_torrent.
start_paused = true in an engine's section (absent = false; not in the template; read at start) holds that engine when it starts: it dials no peer and sends no announce (nor scrape) until you release it. A torrent already in the announce schedule checks again about once a minute (60 s plus a spread of up to 6 s), so it announces about a minute after the release. The schedule takes a catalogue in over up to half an hour after startup (at least 100 torrents per 10 s); a torrent not yet admitted when you release the engine announces when it is admitted.
- A banner sits above the tabs on every tab and cannot be dismissed: Startup pause: {engines} not announcing, "No announces or peer connections are leaving Hydranos. Adjust your rate limits now if you need to, then start. Torrents you paused yourself stay paused.", button Start now (Starting… while it works). It checks again every 10 seconds.
- API:
GET /api/startup-pause→{"held": [...], "holding": true};POST /api/startup-pause/release→{"status": "ok", "released": [...], "holding": false}. Releasing twice is harmless. -
/healthanswersdegraded(still 200) while an engine is held;/api/enginescarriesstart_pausedfor each engine. - The hold is per process, not per torrent: releasing it does not start torrents you stopped.
Not implemented in 4.4: no queue positions — the priority calls answer 409, and a Start over the ceiling is stopped again within 30 s — use Force download (
setForceStartover the shim), a largeractive_downloadsordont_count_slow_torrents.
Known bug in 4.4: the Advanced settings editor shows wrong hints for hoard:
max_connectionsdefault: 8000 (the template has 12000, absent is 0 = no cap),max_uploads_per_torrentdefault: 20 (the template has -1, absent is 0 = 4 slots) andinactivity_timeoutdefault: 90 (the template has 20, and the key does nothing) — trust the tables on this page.
Accepted but ignored in 4.4:
inactivity_timeout(in the template,20for both engines) is read by nothing and not named at startup; its editor hint "Seconds before an idle peer is considered inactive." describes nothing — the peer idle timeout ispeer_timeout(absent or0= 300 s, under 120 raised to 120, live).
The qBittorrent importer brings neither speed limits nor share limits over (Migrating from qBittorrent).
- Engines: Race and Hoard — what an engine is, roles, extra engines.
- Race Drain and Graduation — the Minimum seed declaration share limits wait for.
- qBittorrent Shim and Automation — every shim route and field.
- Configuration: Engines — every engine key.
- Workflows — rules a share limit cannot express.
- REST API — the native routes.
Hydranos wiki — documents v4.4.1. · 🇬🇧 Home · 🇫🇷 Accueil · Changelog · Report an issue
Hydranos 4.4 · 🇬🇧
Start
Install
- Installation & First Run
- Docker
- Linux (bare metal)
- Windows
- Migrating from qBittorrent
- Upgrading from 3.x
Use
- Categories & Routing
- Adding Torrents & Existing Data
- RSS & Automatic Downloads
- Queue, Share & Speed Limits
- Engines: Race & Hoard
- Race Drain & Graduation
- Trackers & Announces
- Jobs, Bulk Actions & Moving Data
- Workflows
Integrate
Network & machines
- Deployment Topologies
- Networking: Ports & Port Forwarding
- VPN & Egress
- Managed WireGuard
- Nodes & Multiple Machines
Operate
- Operating Hydranos
- Monitoring & Logs
- Prometheus Metrics
- Security & Access
- Troubleshooting
- Known Limitations in 4.4
Reference
- Architecture
- Configuration overview
- Config: daemon, auth & global
- Config: engines & race drain
- Config: environment, CLI & signals
Hydranos 4.4 · 🇫🇷
Démarrer
Installer
- Installation & premier démarrage
- Docker
- Linux (bare metal)
- Windows
- Migrer depuis qBittorrent
- Mettre à jour depuis la 3.x
Utiliser
- Catégories & routage
- Ajouter des torrents & données existantes
- Flux RSS & téléchargements automatiques
- File, limites de partage & de débit
- Moteurs : race & hoard
- Drain race & graduation
- Trackers & annonces
- Jobs, actions groupées & déplacement
- Workflows
Intégrer
Réseau & machines
- Topologies de déploiement
- Réseau : ports & redirection
- VPN & sortie réseau
- WireGuard géré
- Nœuds & plusieurs machines
Exploiter
- Exploiter Hydranos
- Supervision & journaux
- Métriques Prometheus
- Sécurité & accès
- Dépannage
- Limites connues de la 4.4
Référence
- Architecture
- Configuration : vue d'ensemble
- Config : démon, auth & global
- Config : moteurs & drain race
- Config : environnement, CLI & signaux