Feat v0.6.4 admin health/metrics tab + cluster merge
All checks were successful
CI/CD / detect-changes (pull_request) Successful in 4s
CI/CD / test-frontend (pull_request) Successful in 5s
CI/CD / test-go-pg (pull_request) Successful in 2m40s
CI/CD / test-sqlite (pull_request) Successful in 2m46s
CI/CD / build-and-deploy (pull_request) Successful in 1m1s
All checks were successful
CI/CD / detect-changes (pull_request) Successful in 4s
CI/CD / test-frontend (pull_request) Successful in 5s
CI/CD / test-go-pg (pull_request) Successful in 2m40s
CI/CD / test-sqlite (pull_request) Successful in 2m46s
CI/CD / build-and-deploy (pull_request) Successful in 1m1s
Admin Health tab under Monitoring with auto-refreshing runtime, DB, cluster, and extension metrics panels. New GET /api/v1/admin/metrics endpoint. Fattened heartbeat JSONB with stack, GC CPU%, extension count, sandbox stats, trigger fires. Sandbox runner and trigger engine now track cumulative execution counters. Event bus tracks publish/deliver counts. Health endpoints consolidated via shared builder. Block renderers (mermaid, katex, csv-table, diff-viewer) no longer require chat. cluster-dashboard package retired — merged into admin Health tab. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -23,16 +23,37 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"go.starlark.net/starlark"
|
||||
|
||||
starlarkjson "go.starlark.net/lib/json"
|
||||
|
||||
"switchboard-core/events"
|
||||
"switchboard-core/metrics"
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/store"
|
||||
)
|
||||
|
||||
// sandboxStats tracks cumulative execution counters for the admin metrics endpoint.
|
||||
var sandboxStats struct {
|
||||
execCount atomic.Int64
|
||||
errorCount atomic.Int64
|
||||
totalDurationNs atomic.Int64
|
||||
}
|
||||
|
||||
// SandboxStats returns cumulative execution counters.
|
||||
func SandboxStats() (execCount, errorCount uint64, avgDurationMs float64) {
|
||||
exec := sandboxStats.execCount.Load()
|
||||
errs := sandboxStats.errorCount.Load()
|
||||
totalNs := sandboxStats.totalDurationNs.Load()
|
||||
if exec > 0 {
|
||||
avgDurationMs = float64(totalNs) / float64(exec) / 1e6
|
||||
}
|
||||
return uint64(exec), uint64(errs), avgDurationMs
|
||||
}
|
||||
|
||||
// RunContext carries per-invocation state that modules need but which
|
||||
// varies per caller (API route vs filter vs task). Nil is safe — modules
|
||||
// that need RunContext fields gracefully degrade.
|
||||
@@ -142,7 +163,20 @@ func (r *Runner) ExecPackage(ctx context.Context, pkg *store.PackageRegistration
|
||||
|
||||
log.Printf(" 🔧 runner: exec %s (%d modules granted)", pkg.ID, len(modules))
|
||||
|
||||
return r.sandbox.ExecWithLoader(ctx, pkg.ID+"/script.star", script, modules, loader)
|
||||
start := time.Now()
|
||||
result, err := r.sandbox.ExecWithLoader(ctx, pkg.ID+"/script.star", script, modules, loader)
|
||||
duration := time.Since(start)
|
||||
|
||||
sandboxStats.execCount.Add(1)
|
||||
sandboxStats.totalDurationNs.Add(int64(duration))
|
||||
status := "success"
|
||||
if err != nil {
|
||||
sandboxStats.errorCount.Add(1)
|
||||
status = "error"
|
||||
}
|
||||
metrics.SandboxExecutionsTotal.WithLabelValues("exec", status).Inc()
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
// loadScript reads the entry point script from disk (primary path)
|
||||
@@ -266,8 +300,20 @@ func (r *Runner) CallEntryPoint(ctx context.Context, pkg *store.PackageRegistrat
|
||||
return nil, result.Output, fmt.Errorf("package %q: %s is not callable", pkg.ID, entryPoint)
|
||||
}
|
||||
|
||||
val, callOutput, err := r.sandbox.Call(ctx, callable, args, kwargs)
|
||||
return val, result.Output + callOutput, err
|
||||
start := time.Now()
|
||||
val, callOutput, callErr := r.sandbox.Call(ctx, callable, args, kwargs)
|
||||
duration := time.Since(start)
|
||||
|
||||
sandboxStats.execCount.Add(1)
|
||||
sandboxStats.totalDurationNs.Add(int64(duration))
|
||||
status := "success"
|
||||
if callErr != nil {
|
||||
sandboxStats.errorCount.Add(1)
|
||||
status = "error"
|
||||
}
|
||||
metrics.SandboxExecutionsTotal.WithLabelValues(entryPoint, status).Inc()
|
||||
|
||||
return val, result.Output + callOutput, callErr
|
||||
}
|
||||
|
||||
// buildModules assembles the module map based on granted permissions.
|
||||
|
||||
Reference in New Issue
Block a user