open
https://gitlab.synchro.net/main/sbbs/-/work_items/1295
A server that always has at least one client connected never recycles. The
Web, FTP, Mail and Services servers check their recycle semaphores (`ctrl/recycle`, `recycle.<server>`, changed `.ini` files, and the `recycle_now` signal from MQTT/sbbsctrl) only when no sessions are active:
| Server | Recycle check is skipped unless |
|---|---|
| Web (`websrvr.cpp`, `web_server()`) | `thread_count <= 2` (+1 with the HTTP logging thread) |
| FTP (`ftpsrvr.cpp`, `ftp_server()`) | `thread_count <= 1` |
| Mail (`mailsrvr.cpp`, `mail_server()`) | `thread_count <= 1` (+1 with sendmail) |
| Services (`services.cpp`, `services_thread()`) | `active_clients() == 0` and no threads pending start |
The terminal server checks its semaphores unconditionally and flags busy
nodes to rerun instead, so it is not affected.
A public web server is rarely idle: crawlers alone keep dozens of sessions
open around the clock. On such a system a recycle request is never acted
on, so anything that relies on a recycle silently does not take effect:
- **TLS certificate renewal.** `letsyncrypt.js` writes the new
`ctrl/ssl.cert` and touches `ctrl/recycle`. The Web Server keeps serving
the old certificate from memory until it is restarted, so an unattended
renewal does not prevent the certificate from expiring.
- **Configuration changes** (`sbbs.ini`, `web_handler.ini`, `mime_types.ini`,
`mailproc.ini`, `services.ini`, etc.) are never loaded.
Nothing is logged, so the sysop sees no sign that the request is pending.
Observed 2026-10-22 on a busy Linux web server (`sbbs d w!`, about 30
clients and 65 threads at any moment): `letsyncrypt.js` renewed the
certificate and touched `ctrl/recycle`; the services, FTP, terminal and
mail servers (another `sbbs` process, idle at the time) logged "Recycle semaphore file detected" within 15 seconds, while the Web Server never did
and continued serving the previous certificate.
#236 described this (check semaphores even when in use, and stop accepting
new connections once a terminate or recycle is flagged). Its fix made the **shutdown** semaphore unconditional; the **recycle** checks remain behind
the idle test.
Possible approaches:
1. Check recycle semaphores on every pass; once one is detected, log it,
stop accepting new connections, let current sessions finish, and
recycle. A drain time limit is needed, after which remaining sessions
are dropped, or a single long download or hung script holds the server
(and refuses all new connections) indefinitely.
2. Independently, reload the TLS certificate (`ctrl/ssl.cert` mtime) without
a recycle, so certificate renewal never needs to refuse connections.
At minimum, log once when a recycle request is detected but deferred
because sessions are active.
*Authored by Claude (Claude Code), on behalf of @rswindell*
--- SBBSecho 3.38-Linux
* Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)