Files
OpenFlare/scripts/live_ch_smoke/main.go
T
ryan 2f60329886 后端与全仓代码质量清理(golangci 扩展集 · 测试质量 · 并发安全 · 文档同步)
代码质量全量清理,零行为变化:golangci 扩展集 13 类 linter(gosec/modernize/perfsprint/canonicalheader/usestdlibvars/wastedassign/intrange/errorlint/forcetypeassert/recvcheck/exhaustive/unparam)全量修复,测试代码质量(testifylint/thelper/usetesting)25→0,frpc 进程生命周期真 bug(进程组击杀)、全仓 go test -race 6 类数据竞争(含 1 个生产竞争)、SPDX license 头补齐 131 文件、前端测试套件 next-intl 迁移后 44 失败→全绿、过期 swagger 文档重新生成、pnpm-workspace 构建审批。

Experiments: #2-#17, #18, #20, #21, #23
Metric: total_issues 108 → 8 (-92.6%)
2026-08-16 21:24:14 +08:00

99 lines
2.7 KiB
Go

// Copyright 2026 Arctel.net
// SPDX-License-Identifier: Apache-2.0
// Package main is a manual smoke tool for ClickHouse app write path.
// Usage (from repo root, with config.yaml and Docker CH up):
//
// go run ./scripts/live_ch_smoke
package main
import (
"context"
"errors"
"fmt"
"os"
"time"
"github.com/Rain-kl/Wavelet/internal/repository"
"github.com/Rain-kl/Wavelet/internal/apps/openflare/chwriter"
db "github.com/Rain-kl/Wavelet/internal/infra/persistence"
"github.com/Rain-kl/Wavelet/internal/model"
)
const (
flushWaitTimeout = 45 * time.Second
listLimit = 5
pollInterval = 2 * time.Second
)
func main() {
if err := run(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func run() error {
if !db.ChConnReady() {
return errors.New("ChConn not ready — check config.yaml clickhouse.enabled")
}
ctx := context.Background()
chwriter.Init(ctx)
defer func() { _ = chwriter.Stop(ctx) }()
now := time.Now().UTC()
nodeID := "e2e-app-" + now.Format("150405")
if err := repository.InsertOpenFlareMetricSnapshot(ctx, &model.OpenFlareMetricSnapshot{
NodeID: nodeID, CapturedAt: now, CPUUsagePercent: 41.2,
MemoryUsedBytes: 123, MemoryTotalBytes: 1000,
StorageUsedBytes: 456, StorageTotalBytes: 2000,
DiskReadBytes: 11, DiskWriteBytes: 22, NetworkRxBytes: 33, NetworkTxBytes: 44,
}); err != nil {
return fmt.Errorf("insert: %w", err)
}
fmt.Println("queued", nodeID)
if err := waitForSnapshot(ctx, nodeID, now); err != nil {
return err
}
if err := assertLatestIncludes(ctx, nodeID, now); err != nil {
return err
}
for _, s := range chwriter.WriterStats() {
fmt.Printf("writer %s running=%v depth=%d drops=%d flush_err=%d\n",
s.Name, s.Running, s.Depth, s.Drops, s.FlushErrors)
}
return nil
}
func waitForSnapshot(ctx context.Context, nodeID string, now time.Time) error {
deadline := time.Now().Add(flushWaitTimeout)
for time.Now().Before(deadline) {
rows, err := repository.ListOpenFlareMetricSnapshotsSince(ctx, nodeID, now.Add(-time.Minute), listLimit)
if err != nil {
return fmt.Errorf("list: %w", err)
}
if len(rows) > 0 {
fmt.Printf("OK flushed id=%d cpu=%.1f\n", rows[0].ID, rows[0].CPUUsagePercent)
return nil
}
time.Sleep(pollInterval)
}
return errors.New("not flushed within timeout")
}
func assertLatestIncludes(ctx context.Context, nodeID string, now time.Time) error {
latest, err := repository.ListOpenFlareLatestMetricSnapshotsSince(ctx, "", now.Add(-time.Hour))
if err != nil {
return fmt.Errorf("latest: %w", err)
}
for _, r := range latest {
if r != nil && r.NodeID == nodeID {
fmt.Println("OK latest-per-node includes node")
return nil
}
}
return fmt.Errorf("latest-per-node missing node %s", nodeID)
}