par keyword is not supported in the PlantUML version on the Gitea runner. Replace with a group block (universally supported) and a spanning note to convey the parallelism.
90 lines
3.1 KiB
Plaintext
90 lines
3.1 KiB
Plaintext
@startuml seq-polling
|
||
!theme plain
|
||
title sofarr — Background Polling Cycle
|
||
|
||
|
||
participant "index.js\n(startup)" as entry
|
||
participant "Poller" as poller
|
||
participant "Config" as config
|
||
participant "SABnzbd\n(per instance)" as sab
|
||
participant "Sonarr\n(per instance)" as sonarr
|
||
participant "Radarr\n(per instance)" as radarr
|
||
participant "qBittorrent\nClient" as qbt
|
||
participant "MemoryCache" as cache
|
||
|
||
== Startup ==
|
||
entry -> poller : startPoller()
|
||
activate poller
|
||
|
||
alt POLL_INTERVAL > 0
|
||
poller -> poller : pollAllServices() (immediate)
|
||
poller -> poller : setInterval(pollAllServices,\nPOLL_INTERVAL)
|
||
else POLL_INTERVAL = 0
|
||
poller --> entry : "Polling disabled, on-demand mode"
|
||
end
|
||
|
||
== Poll Cycle ==
|
||
poller -> poller : Check: polling flag?\n(skip if concurrent)
|
||
poller -> poller : polling = true
|
||
poller -> poller : start = Date.now()
|
||
|
||
poller -> config : getSABnzbdInstances()
|
||
config --> poller : [{ id, url, apiKey }]
|
||
poller -> config : getSonarrInstances()
|
||
config --> poller : [{ id, url, apiKey }]
|
||
poller -> config : getRadarrInstances()
|
||
config --> poller : [{ id, url, apiKey }]
|
||
|
||
note over poller, cache
|
||
All 9 fetches run in parallel via Promise.all,
|
||
each wrapped in timed(). Shown sequentially below.
|
||
end note
|
||
|
||
group Parallel API Fetches (Promise.all)
|
||
poller -> sab : GET /api?mode=queue
|
||
sab --> poller : { queue: { slots, status, speed } }
|
||
poller -> sab : GET /api?mode=history&limit=10
|
||
sab --> poller : { history: { slots } }
|
||
poller -> sonarr : GET /api/v3/tag
|
||
sonarr --> poller : [{ id, label }]
|
||
poller -> sonarr : GET /api/v3/queue?includeSeries=true
|
||
sonarr --> poller : { records: [{ seriesId, series, ... }] }
|
||
poller -> sonarr : GET /api/v3/history?pageSize=10
|
||
sonarr --> poller : { records: [{ seriesId, ... }] }
|
||
poller -> radarr : GET /api/v3/queue?includeMovie=true
|
||
radarr --> poller : { records: [{ movieId, movie, ... }] }
|
||
poller -> radarr : GET /api/v3/history?pageSize=10
|
||
radarr --> poller : { records: [{ movieId, ... }] }
|
||
poller -> radarr : GET /api/v3/tag
|
||
radarr --> poller : [{ id, label }]
|
||
poller -> qbt : getTorrents()
|
||
qbt --> poller : [{ name, progress, ... }]
|
||
end
|
||
|
||
poller -> poller : Record per-task timings\nlastPollTimings = { totalMs,\ntimestamp, tasks: [{label, ms}] }
|
||
|
||
poller -> poller : cacheTTL = POLL_INTERVAL × 3
|
||
|
||
poller -> cache : set('poll:sab-queue', ..., cacheTTL)
|
||
poller -> cache : set('poll:sab-history', ..., cacheTTL)
|
||
poller -> cache : set('poll:sonarr-tags', ..., cacheTTL)
|
||
|
||
note over poller : Tag queue records with\n_instanceUrl on embedded\nseries/movie objects
|
||
|
||
poller -> cache : set('poll:sonarr-queue', ..., cacheTTL)
|
||
poller -> cache : set('poll:sonarr-history', ..., cacheTTL)
|
||
poller -> cache : set('poll:radarr-queue', ..., cacheTTL)
|
||
poller -> cache : set('poll:radarr-history', ..., cacheTTL)
|
||
poller -> cache : set('poll:radarr-tags', ..., cacheTTL)
|
||
poller -> cache : set('poll:qbittorrent', ..., cacheTTL)
|
||
|
||
poller -> poller : Notify SSE subscribers\npollSubscribers.forEach(cb => cb())
|
||
|
||
note over poller : Each registered SSE client\ncallback rebuilds its payload\nand writes a data: frame
|
||
|
||
poller -> poller : polling = false\nlog elapsed time
|
||
|
||
deactivate poller
|
||
|
||
@enduml
|