| semantic-links |
|
|---|
This document describes the tracker application's current implementation of background jobs and task ownership. It is not the final shutdown architecture. The target design is being developed in shutdown-overhaul EPIC #1488 and its draft PR #1993.
- Direct component: a named component future spawned directly by
JobManagerinto itsJoinSet. - Legacy job: the pre-spawned UDP IP-ban cleanup handle retained by
JobManageroutside theJoinSetuntil it receives its own periodic-job migration. - Owner:
JobManagerowns direct component tasks and the retained legacy handles; a direct component owns any nested server task it starts. - Service: a runtime capability stored in an application or instance container. Services may be shared between instances or owned by one instance.
- Instance: a configured UDP or HTTP listener, such as one element of
[[udp_trackers]].
Tokio jobs are not operating-system processes. An unmanaged job can nevertheless outlive the component that logically owns it, retain resources, and make shutdown unreliable. This document calls such a task unmanaged or orphaned, not a zombie process.
maincallsapp::start.bootstrap::app::setuploads configuration, initializes shared services, and constructsAppContainer.app::startloads required persisted data, thenstart_jobscreates aJobManagerand starts application jobs and service instances.- On
Ctrl+C,maincallsJobManager::cancel, then waits for registered direct components and transitional legacy jobs throughJobManager::wait_for_allunder one ten-second process-wide grace period.
flowchart TD
Main[main] -->|app::start| Setup[bootstrap::app::setup]
Setup --> Container[AppContainer]
Main --> Start[app::start]
Start --> Jobs[start_jobs]
Jobs --> Manager[JobManager]
Jobs --> BanCleanup[udp_ban_cleanup job]
Jobs --> UdpInstances[UDP instance jobs]
Jobs --> OtherJobs[Other background jobs]
Container --> SharedBan[shared BanService]
BanCleanup --> SharedBan
UdpInstances --> SharedBan
Main -->|Ctrl+C| Cancel[JobManager::cancel]
Cancel --> Manager
Manager -->|shared CancellationToken| BanCleanup
Main -->|wait up to 10 seconds total| Wait[JobManager::wait_for_all]
Wait --> Manager
Every spawned task has an explicit owner. JobManager::spawn directly creates
and owns direct component tasks in its JoinSet; it does not receive their
JoinHandles. Components retain ownership of their nested server handles and
must signal, join, or deliberately abort them before completion. The narrow
legacy registry retains only the pre-spawned periodic handles that cannot be
adopted by a JoinSet without a wrapper task.
JobManager::cancel supplies one shared CancellationToken for cooperative
shutdown. wait_for_all applies one common deadline concurrently to direct
components and retained legacy handles. On expiry it aborts and joins all
remaining work; direct components use drop-safe cleanup to prevent a nested
server from becoming detached when the outer component is aborted.
The job's ownership follows the lifetime of the service or data it operates on, not merely the listener that happened to start it. A shared service has one application-owned job; an instance-owned service can have one instance-owned job.
Issue #1453 applies this ownership rule to the UDP IP-ban cleanup task.
UdpTrackerCoreServices owns one BanService shared by every configured UDP
tracker instance. Previously, each UDP listener launcher spawned a cleanup task
for that same shared service. With multiple UDP listeners, the application
therefore ran multiple cleanup tasks that reset the same ban data.
The UDP listener instances, their event-listener jobs, and the cleanup task now
start as one configuration-gated UDP service group. The cleanup task is one
application-owned udp_ban_cleanup job:
app::start_jobsstarts the group only when UDP listeners are requested and allowed: at least one is configured and the tracker is not in private mode.- It registers the cleanup job with
JobManagerbefore starting UDP listener instances. - It receives the manager's shared
CancellationTokenand exits cooperatively when cancellation is requested. - The listener launcher no longer spawns cleanup tasks.
This is a concrete improvement in lifecycle control, but it does not imply that all jobs already follow the desired ownership model.
The current JobManager directly owns named component futures in a JoinSet
and keeps a narrow compatibility registry only for the pre-spawned UDP
ban-cleanup periodic job. All of those tasks share one shutdown deadline, but
the legacy job is not a direct JoinSet component. It is transitional until
the UDP ban-cleanup periodic-job migration is complete.
It is not yet a complete task-supervision system.
In particular, the current architecture does not yet define a complete hierarchy of parent and child jobs, uniform cancellation support for every job, state reporting, restart policy, or richer parent-child communication. Those concerns belong to shutdown-overhaul EPIC #1488 and draft PR #1993. Changes to this document should describe verified current behavior until that design is accepted.