- docs/ARCHITECTURE.md: full system overview, technology stack, directory structure, component architecture, data flow, auth, polling/caching, download matching pipeline, API reference, frontend architecture, configuration, deployment guide - docs/diagrams/component.puml: system component diagram - docs/diagrams/seq-auth.puml: authentication sequence diagram - docs/diagrams/seq-dashboard.puml: dashboard request sequence diagram - docs/diagrams/seq-polling.puml: background polling cycle sequence - docs/diagrams/class-server.puml: server-side class/module diagram - docs/diagrams/class-data.puml: data model / entity diagram - docs/diagrams/state-ui.puml: frontend UI state diagram - docs/diagrams/state-poller.puml: poller state diagram - docs/diagrams/activity-matching.puml: download matching activity diagram
66 lines
1.7 KiB
Plaintext
66 lines
1.7 KiB
Plaintext
@startuml state-poller
|
||
!theme plain
|
||
title sofarr — Poller State Diagram
|
||
|
||
[*] --> CheckConfig : startPoller()
|
||
|
||
state CheckConfig <<choice>>
|
||
CheckConfig --> Disabled : POLL_INTERVAL = 0\nor 'off' / 'false'
|
||
CheckConfig --> Idle : POLL_INTERVAL > 0
|
||
|
||
state Disabled {
|
||
state "On-demand mode\nNo background timer" as od
|
||
od : Data fetched only when\na dashboard request\nfinds empty cache
|
||
}
|
||
|
||
Disabled --> Polling : pollAllServices()\n(triggered by dashboard request)
|
||
Polling --> Disabled : Poll complete\n(return to on-demand)
|
||
|
||
state Idle {
|
||
state "Waiting for\nnext interval" as waiting
|
||
}
|
||
|
||
Idle --> Polling : setInterval fires\nor immediate first poll
|
||
|
||
state Polling {
|
||
state "polling = true" as lock
|
||
state "Fetching all services\n(Promise.all)" as fetching
|
||
state "Storing results\nin cache" as storing
|
||
state "Recording timings" as timing
|
||
|
||
[*] --> lock
|
||
lock --> fetching
|
||
fetching --> storing : All promises resolved
|
||
fetching --> ErrorState : Any individual service\nerror (caught per-service)
|
||
storing --> timing
|
||
timing --> [*] : polling = false
|
||
}
|
||
|
||
state ErrorState as "Handle Error" {
|
||
state "Log error\npolling = false" as err
|
||
}
|
||
|
||
ErrorState --> Idle : Next interval
|
||
Polling --> Idle : Poll complete\n(back to waiting)
|
||
|
||
state "Concurrent Poll\nAttempt" as skip {
|
||
state "polling === true\n→ skip" as sk
|
||
}
|
||
|
||
Idle --> skip : Interval fires while\nprevious still running
|
||
skip --> Idle : Log "still running,\nskipping"
|
||
|
||
note right of Polling
|
||
**Cache TTL**: POLL_INTERVAL × 3
|
||
Ensures data survives between polls
|
||
even if one cycle is slow.
|
||
end note
|
||
|
||
note right of Disabled
|
||
**Cache TTL**: 30000ms (30s)
|
||
After expiry, next dashboard
|
||
request triggers a fresh poll.
|
||
end note
|
||
|
||
@enduml
|