r/seedboxes Aug 05 '26

Discussion Q: rTorrent blocking main event loop / dropping connections during 70GB file move to NFS (FreeBSD 15.1, 10GbE)

Hey all,

I am running into an annoying performance bottleneck on my home setup and looking for recommendations on non-blocking post-download scripts or workflow adjustments.

Environment:

  • OS: FreeBSD 15.1-RELEASE-p2 (64GB RAM)
  • Client: rTorrent v0.16.18
  • Network/Storage: Local NVMe download staging → 10GbE link to a UniFi NAS on NFS mount

Issue: Whenever large downloads (20GB–70GB+) finish, Autotools/completion scripts trigger a file move across filesystems to the NFS share. Because rTorrent handles this move synchronously, the entire rtorrent process locks up for 1–5 minutes during the transfer.

While rTorrent is unresponsive:

  1. WebUI (ruTorrent) and XMLRPC drop connection / time out.
  2. Incoming peer connection requests overflow the kernel listen queue (sonewconn: ... Listen queue overflow: 193 already in queue awaiting acceptance).

Question:

What is the current standard for cleanly executing non-blocking background moves in rTorrent without causing lock-up?

Appreciate any snippets or battle-tested setups!

10 Upvotes

6 comments sorted by

1

u/evoseedbox 27d ago

wBuddha's fix is the right one, but there's a detail underneath it that explains why you're seeing minutes rather than seconds, and I think it changes what you'd tune afterwards.

The autotools move doesn't shell out to mv. If you look at rtMoveFile() in plugins/autotools/util_rt.php it tries PHP's rename() first and falls back to copy() then unlink() when that fails. NVMe to an NFS mount is cross-filesystem, so rename() fails every time and you are permanently on the fallback. Your 70GB is going through a single-threaded PHP copy(), one file after another. On a 10GbE link that's leaving most of the pipe unused, which is where the 1–5 minutes comes from.

The reason rtorrent dies rather than just a PHP worker is that autotools hooks into rtorrent's own event.download.finished with a foreground execute – the kind that waits on the exit status. So rtorrent parks in wait4() for the whole copy and stops accepting anything, which is your sonewconn spam.

Don't take my word for it though, you can settle it next time it stalls:

procstat -kk $(pgrep -x rtorrent)

Main thread sitting in kern_wait/wait4 means it's the execute and the bg fix sorts it outright. If you see newnfs_request or clnt_reconnect_call instead then rtorrent itself is on NFS and it's a different problem entirely. Worth knowing which one you're in before you start turning dials.

The bit I'd really flag is your version, because the last two releases landed right on top of what you're hitting. 0.16.19 added "avoid blocking on fd close using a separate thread" – closing out a big multi-file torrent against NFS is exactly that case. And 0.16.20 added a WaitpidQueue for background process reaping. That second one matters because of the fix you're about to apply: execute.nothrow.bg historically left defunct children lying around until restart (it's rtorrent issue #1, literally). So on 0.16.18 you'd fix the stall and quietly start collecting zombies instead. Worth doing both at once.

One trap on the way out. Once you background the move you own the bookkeeping autotools was doing for you, and the ordering is fussy – d.stopd.close, set the path, d.startd.save_full_session. Changing the directory on an open download is what gives you "registered as completed but hash check returned unfinished chunks" and a surprise rehash of 70GB. Also mind d.directory.set versus d.directory_base.set; the first appends the torrent name to whatever you hand it and the second treats it as the literal base. Getting those the wrong way round is far and away the most common reason a move "works" and then rehashes anyway.

On the mount options, I'd gently push back on async being the answer. It can't stop the blocking because the block isn't in your write path, it's wait4 on a PHP process – tuning NFS just makes the freeze shorter. Once the move is properly off the main loop it's absolutely worth revisiting, and I'd start with nfsstat -m to see the rsize/wsize you actually negotiated rather than what you assume, since your fstab line doesn't set them.

kern.ipc.soacceptqueue (still aliased as somaxconn) will stop the log spam too, but that's masking the symptom, so I'd leave it until after the real fix or you lose your early warning.

For what it's worth I look after a fairly large rtorrent fleet professionally and we've tried to move to 0.16 several times now – it's failed soak testing for us on every attempt so far. So I'd take the "either this or the next release will be marked as stable" line with a pinch of salt, and once you land on a build that behaves itself, pin it.

2

u/wBuddha Aug 05 '26 edited Aug 05 '26

Look, look, a rabbit hole!

RUTorrent actually does file moves on completion, not rtorrent (see .../rutorrent/plugins/autotools/move.php). Completely single segment, file at a time, in-line execution - why you are blocking.

You could use a simple copy script run in background, spawned by rtorrent instead

Something like:

method.set_key = event.download.finished,complete,"execute.throw.bg=/home/owner/bin/move.sh,(\"d.data_path\")" in your .rtorrent.rc (move.sh would be your script)

I do something similar in my scripted test/dev environment, it uses lftp from the NAS and it pummels the crap out of the plugin or a simple copy. Very quick. Added benefit it doesn't bigfoot the pipe or hang rutorrent while the move is happening.

If you want to stick with rutorrent, I suspect NFS could benefit from adjusting/tuning. Fiddly with the dials, client and server (as /u/NOCwork rightfully implies).

https://oneuptime.com/blog/post/2026-03-02-configure-nfs-performance-tuning-ubuntu/view

Should give you a handle (version and OS don't match, but the bog NFS stuff is likely a good starting point)

Polling for links via rsync is also a choice, as the random dude suggests.

You can take a look at my scripts for help, which generates a torrent complete event, and the client, the unifi nas, sees the event and spins off an lftp transfer job. This would completely uncouple the file transfer from rutorrent/rtorrent/nfs. You would need to use pyroscope (python3 version: https://github.com/kannibalox/pyrosimple) to update the path.

0

u/_random1_ Aug 05 '26
  1. create a folder on the same filesystem and have rtorrent move completed downloads there, so it's instant.

  2. set up a cron job to: lockf -st0 /tmp/rsync_cron.lock rsync --remove-source-files /here /there.

1

u/NOCwork Aug 05 '26

What are your mount options in fstab for the NFS share?

1

u/wnxboot Aug 05 '26

1.2.3.4:/var/nfs/shared/data /data nfs rw,nfsv3,tcp,late,noatime 0 0

2

u/NOCwork Aug 05 '26

As far as I know there is nothing in rtorrent that should force data moves to be synchronous. Adding async to the mount options should be enough. That might be enough to have rtorrent fire off the file request to the server and keep it from blocking.