seq-auth: - startAutoRefresh() -> startSSE(), stopAutoRefresh() -> stopSSE() - Cookie secure flag: 'secure (prod)' -> 'secure (if TRUST_PROXY)' component: - Fix typo creatApp -> createApp - Add GET /csrf, POST /logout to browser->auth arrow - Add GET /stream (SSE) to browser->dashboard arrow class-server: - Add subscribers Set, onPollComplete(), offPollComplete() to Poller class class-data: - Add SSE Event /stream shape alongside API Response /user-downloads - Add sser *-- dl relationship state-ui: - Fix invalid multi-line transition labels with raw Unicode arrows (broke PlantUML parser); replace with valid \n escapes on single line seq-dashboard, seq-polling, state-poller, activity-matching: - Whitespace touch to trigger render-diagrams CI workflow
69 lines
1.8 KiB
Plaintext
69 lines
1.8 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 --> notifying : Cache updated
|
||
state "Notifying SSE\nsubscribers" as notifying
|
||
notifying --> 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
|