fix(iot): пагинация — tiebreaker ts DESC,id DESC + потолок limit; точный лог (Этап 5)

- QueryTelemetry: ORDER BY ts DESC, id DESC (был без tiebreaker → нестабильная
  пагинация при одинаковых ts).
- ListIoTDevices: limit дефолт 100, потолок 1000 (ошибка парсинга больше не даёт
  безлимитный запрос).
- Логи 'batch dropped' → 'валидные строки — построчно' (после fallback батч НЕ
  теряется целиком).
This commit is contained in:
Repinoid
2026-10-10 19:17:25 +03:00
parent f3927fdf11
commit 38e3f65c21
2 changed files with 22 additions and 10 deletions
+15 -3
View File
@@ -221,15 +221,27 @@ func (h *Handler) CreateIoTDevice(w http.ResponseWriter, r *http.Request) {
}
// ListIoTDevices — GET /v1/namespaces/{ns}/iot/devices (без паролей).
// Пагинация: ?limit=N&offset=M (0 = без ограничения).
// Пагинация: ?limit=N&offset=M. limit — дефолт 100, потолок 1000 (защита от
// безлимитного запроса при ошибке парсинга).
func (h *Handler) ListIoTDevices(w http.ResponseWriter, r *http.Request) {
ns := pathVar(r, "namespace")
if ns == "" {
ns = "default"
}
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
offset, _ := strconv.Atoi(r.URL.Query().Get("offset"))
// limit: дефолт 100, потолок 1000 — иначе ошибка парсинга/омиссия = безлимит
// (ревью 2026-10-10).
limit := 100
if v, err := strconv.Atoi(r.URL.Query().Get("limit")); err == nil && v > 0 {
limit = v
}
if limit > 1000 {
limit = 1000
}
offset := 0
if v, err := strconv.Atoi(r.URL.Query().Get("offset")); err == nil && v > 0 {
offset = v
}
devices, err := h.Devices.List(r.Context(), ns, limit, offset)
if err != nil {