Files
silo-server/internal/playback/directplay_metrics.go
ee31a1f0e2 feat(playback): formalize resumable direct streams and stall observability (#464)
* feat(playback): formalize resumable direct streams and stall observability

Implements #443: strong stat-based ETag + If-Range on original-file direct
play (via http.ServeContent), stream-end outcome classification in
RollingDeadlineWriter (stalled_reap vs client_gone vs completed) with a
structured log event and Prometheus counters, the direct_stream_resume_v1
protocol-v3 capability, and a contract doc. Progressive remux is explicitly
excluded from the resume contract.

Code written by OpenAI Codex CLI (gpt-5.6-sol) from a Claude-authored spec;
reviewed and verified by Claude.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(playback): harden direct stream resume contract

* test(playback): cover resume platform contracts

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 14:22:12 -04:00

45 lines
1.6 KiB
Go

package playback
import (
"net/http"
"github.com/Silo-Server/silo-server/internal/httpstream"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
)
var (
directStreamActive = promauto.NewGauge(prometheus.GaugeOpts{
Name: "silo_direct_stream_active",
Help: "Number of original-file direct streams currently being served.",
})
directStreamEnds = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "silo_direct_stream_ends_total",
Help: "Number of original-file direct streams by terminal outcome.",
}, []string{"outcome"})
directStreamRangeResumes = promauto.NewCounter(prometheus.CounterOpts{
Name: "silo_direct_stream_range_resumes_total",
Help: "Number of successful original-file byte-range resumes after byte zero.",
})
directStreamInvalidRanges = promauto.NewCounter(prometheus.CounterOpts{
Name: "silo_direct_stream_invalid_range_total",
Help: "Number of original-file direct stream requests rejected with HTTP 416.",
})
directStreamBytesSent = promauto.NewCounter(prometheus.CounterOpts{
Name: "silo_direct_stream_bytes_sent_total",
Help: "Number of original-file direct stream response body bytes sent.",
})
)
func recordDirectStreamEnd(outcome httpstream.StreamOutcome, status int, bytesSent, rangeStart int64) {
directStreamActive.Dec()
directStreamEnds.WithLabelValues(string(outcome)).Inc()
directStreamBytesSent.Add(float64(bytesSent))
if status == http.StatusPartialContent && rangeStart > 0 {
directStreamRangeResumes.Inc()
}
if status == http.StatusRequestedRangeNotSatisfiable {
directStreamInvalidRanges.Inc()
}
}