// Изменено: 2026-03-07 // invocations.go — GET-handlers для логов вызовов функций. // Данные читаются из PostgreSQL (invocations таблица). // POST /invoke остаётся для будущего прямого вызова (v2). package handler import ( "net/http" "strconv" ) // invocationResponse — ответ при чтении записи вызова. type invocationResponse struct { ID string `json:"id"` FunctionName string `json:"function_name"` Namespace string `json:"namespace"` Status string `json:"status"` DurationMs int32 `json:"duration_ms"` HTTPStatus *int32 `json:"http_status,omitempty"` // nil для cron триггеров Logs string `json:"logs,omitempty"` TriggerType string `json:"trigger_type"` CreatedAt string `json:"created_at"` } // ListInvocations — GET /v1/namespaces/{namespace}/functions/{name}/invocations // Возвращает последние limit вызовов (default 50, max 200). func (h *Handler) ListInvocations(w http.ResponseWriter, r *http.Request) { ns := namespace(r) fnName := pathVar(r, "name") limit := 50 if q := r.URL.Query().Get("limit"); q != "" { if v, err := strconv.Atoi(q); err == nil && v > 0 && v <= 200 { limit = v } } rows, err := h.PG.ListInvocations(r.Context(), fnName, ns, limit) if err != nil { h.Log.Error("list invocations", "fn", fnName, "ns", ns, "err", err) writeJSON(w, http.StatusInternalServerError, errResp(err.Error())) return } result := make([]invocationResponse, 0, len(rows)) for _, row := range rows { result = append(result, invocationResponse{ ID: row.ID, FunctionName: row.FunctionName, Namespace: row.Namespace, Status: row.Status, DurationMs: row.DurationMs, HTTPStatus: row.HTTPStatus, Logs: row.Logs, TriggerType: row.TriggerType, CreatedAt: row.CreatedAt.Format("2006-01-02T15:04:05Z"), }) } writeJSON(w, http.StatusOK, result) }