Apprise URLs: a line may set Apprise's socket timeouts (rto=, cto=), so one connection can hold the shared scheduler for hours #17
Labels
No labels
bug
documentation
enhancement
security
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo-apprise#17
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found on 2026-09-29 in a read-only review of postulo-apprise at
7637d899d, inspecting the server objectsbuild()returns for lines that carry Apprise's generic arguments, and followingsend()back to the scheduler's pass in the core.Every Apprise URL accepts
rto=andcto=, the socket read and connect timeouts (4 seconds each by default), and the plugin hands lines to Apprise unchanged.send()is called synchronously from the scheduler's single pass, with no deadline around a notifier. A line that raises the read timeout and points at an endpoint that accepts the connection and never answers keeps the pass waiting for as long as the line says. The core gives its own client a fixed 10-second timeout for this reason; the Apprise path has no ceiling.src/postulo_apprise/notifier.py:59-71(build, which adds each line as typed);:205and:236(client.notify(...)intestandsend, with nothing around them). In Apprise 1.13.1,url.py:293-304reads both values from the line andurl.py:823-826passes them torequestsas the timeout. In the core:notifications/service.py:72(plugin.send(...), no deadline),notifications/management/commands/send_due_reminders.py:55-98(onenotifyper due reminder, every account in turn) and:187-196(one_pass, where document copies, webhooks and syncs wait behind the reminders).json://line withrto=86400&cto=86400passesvalidate()({}), and the server the plugin builds reportssocket_connect_timeout=86400.0,socket_read_timeout=86400.0. Nothing innotifier.pyreads or caps either value; the form caps only the field's length (20,000 characters, in the core'splugins/forms.py:127), not the number of lines. At that account's next due reminder the scheduler waits for the endpoint until the timeout runs out before it moves on.docker/Dockerfile:354in the core) ends it.build(), clamp each server'ssocket_connect_timeoutandsocket_read_timeoutto a small ceiling (the core's 10 seconds is the natural one), or refuse on the form a line that setsrtoorctoabove it.client.notify()with one overall deadline per send, and report the connection as failed when it passes.Done when
tests/test_apprise.pyshows that a line with a largertoandctoyields a server whose two timeouts are at the ceiling (or is refused byvalidate()), and that a line without them is unchanged.tests/test_apprise.py, withapprise.Apprise.notifyreplaced by one that blocks, showssend()raising once the overall deadline has passed.Fixed by pull request #23.