feat: billing layer v1.3.86 — PostgreSQL statistics

- internal/billing: Store interface + pgStore (pgx/v5 pool) + NoopStore
- factory.go: NewStore() from BILLING_DSN env var (NoopStore fallback)
- Server.billing: injected into Config, initialized in main
- handleInvokeFunction: record invocation (TriggerConsole)
- invokeInternalFunction: record invocation (TriggerHTTP)
- handleCreateFunction: record event_type=create
- handleCloneFunction: record event_type=clone
- handleDeleteFunction: record event_type=delete
- table: invocations (namespace, function_name, trigger_type, duration_ms, status_code...)
- BILLING_DSN added to console.yaml
- pgx/v5 added to go.mod/go.sum
This commit is contained in:
“Naeel”
2026-05-10 08:26:42 +04:00
parent 11c90bac9e
commit aaa1b9a82d
15 changed files with 327 additions and 6 deletions
+11
View File
@@ -19,6 +19,7 @@ import (
"strings"
"time"
"fission-console/internal/billing"
"fission-console/internal/fission"
"fission-console/internal/runtime"
@@ -241,6 +242,16 @@ func (s *Server) handleCloneFunction(w http.ResponseWriter, r *http.Request, src
return
}
s.billing.RecordInvocation(billing.Invocation{
Namespace: ns,
FunctionName: req.NewName,
TriggerType: billing.TriggerEvent,
StartedAt: now,
StatusCode: http.StatusCreated,
RecordedBy: "console",
EventType: "clone",
})
writeAnyJSON(w, http.StatusCreated, map[string]any{
"name": req.NewName,
"cloned_from": srcName,
+11
View File
@@ -22,6 +22,7 @@ import (
"strings"
"time"
"fission-console/internal/billing"
"fission-console/internal/fission"
"fission-console/internal/model"
"fission-console/internal/runtime"
@@ -275,6 +276,16 @@ func (s *Server) handleCreateFunction(w http.ResponseWriter, r *http.Request) {
return
}
s.billing.RecordInvocation(billing.Invocation{
Namespace: ns,
FunctionName: req.Name,
TriggerType: billing.TriggerEvent,
StartedAt: now,
StatusCode: http.StatusCreated,
RecordedBy: "console",
EventType: "create",
})
writeAnyJSON(w, http.StatusCreated, map[string]any{
"name": req.Name,
"package": pkgName,
+11
View File
@@ -21,6 +21,7 @@ import (
"strings"
"time"
"fission-console/internal/billing"
"fission-console/internal/fission"
corev1 "k8s.io/api/core/v1"
@@ -228,6 +229,16 @@ func (s *Server) handleDeleteFunction(w http.ResponseWriter, r *http.Request, na
// (reconciler NS удалён — за FISSION_RESOURCE_NAMESPACES теперь отвечает Layer 1 NSWatcher)
s.billing.RecordInvocation(billing.Invocation{
Namespace: ns,
FunctionName: name,
TriggerType: billing.TriggerEvent,
StartedAt: time.Now(),
StatusCode: http.StatusOK,
RecordedBy: "console",
EventType: "delete",
})
writeAnyJSON(w, http.StatusOK, map[string]any{"deleted": true, "name": name, "package": pkgName})
}
+37 -2
View File
@@ -22,6 +22,7 @@ import (
"strings"
"time"
"fission-console/internal/billing"
"fission-console/internal/fission"
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -202,9 +203,26 @@ func (s *Server) handleInvokeFunction(w http.ResponseWriter, r *http.Request, na
defer resp.Body.Close()
respBody, _ := io.ReadAll(resp.Body)
durationMS := time.Since(start).Milliseconds()
s.billing.RecordInvocation(billing.Invocation{
Namespace: ns,
FunctionName: name,
TriggerType: billing.TriggerConsole,
Route: invokeURL,
HTTPMethod: invokeMethod,
StartedAt: start,
DurationMS: durationMS,
StatusCode: resp.StatusCode,
RequestBytes: int64(len(bodyBytes)),
ResponseBytes: int64(len(respBody)),
RecordedBy: "console",
EventType: "invoke",
})
writeAnyJSON(w, http.StatusOK, map[string]any{
"status": resp.StatusCode,
"latency_ms": time.Since(start).Milliseconds(),
"latency_ms": durationMS,
"response_raw": string(respBody),
})
}
@@ -311,9 +329,26 @@ func (s *Server) invokeInternalFunction(w http.ResponseWriter, r *http.Request,
defer resp.Body.Close()
respBody, _ := io.ReadAll(resp.Body)
durationMS := time.Since(start).Milliseconds()
s.billing.RecordInvocation(billing.Invocation{
Namespace: namespace,
FunctionName: functionName,
TriggerType: billing.TriggerHTTP,
Route: extraPath,
HTTPMethod: r.Method,
StartedAt: start,
DurationMS: durationMS,
StatusCode: resp.StatusCode,
RequestBytes: int64(len(bodyBytes)),
ResponseBytes: int64(len(respBody)),
RecordedBy: "console",
EventType: "invoke",
})
writeAnyJSON(w, http.StatusOK, map[string]any{
"status": resp.StatusCode,
"latency_ms": time.Since(start).Milliseconds(),
"latency_ms": durationMS,
"response_raw": string(respBody),
})
}
+6
View File
@@ -13,6 +13,7 @@ import (
"time"
"fission-console/internal/auth"
"fission-console/internal/billing"
"fission-console/internal/cloud"
"fission-console/internal/fission"
"fission-console/ui"
@@ -59,6 +60,9 @@ type Server struct {
// nsManager управляет жизненным циклом пользовательских namespace-ов.
nsManager *cloud.NSManager
// billing — слой записи статистики вызовов. NoopStore если BILLING_DSN не задан.
billing billing.Store
}
// Config содержит все параметры для создания Server.
@@ -76,6 +80,7 @@ type Config struct {
Authenticator auth.Authenticator // слой аутентификации
LLMUrl string
LLMKey string
Billing billing.Store // слой статистики (NoopStore если не задан)
}
// NewServer создаёт и настраивает HTTP Server со всеми зависимостями.
@@ -96,6 +101,7 @@ func NewServer(cfg Config) *Server {
llmURL: cfg.LLMUrl,
llmKey: cfg.LLMKey,
nsManager: cloud.NewNSManager(cfg.Dyn),
billing: cfg.Billing,
}
}