package cli import ( "context" "errors" "net" "net/http" "os/signal" "syscall" "time" "github.com/spf13/cobra" "gitea.mynodes.xyz/ilker/llmgw/internal/sim" ) func newSimEngineCmd() *cobra.Command { cfg := sim.Default() var listen string cmd := &cobra.Command{ Use: "sim-engine", Short: "OpenAI uyumlu sahte inference engine (test için)", Long: "Gerçek bir engine'in router açısından önemli davranışlarını simüle eder:\n" + "continuous batching, KV blok muhasebesi, prefix cache, vLLM formatında /metrics.\n" + "Router'ı GPU olmadan test etmek için kullanılır.", RunE: func(cmd *cobra.Command, _ []string) error { log := logger() eng := sim.New(cfg) defer eng.Close() srv := &http.Server{ Addr: listen, Handler: sim.NewServer(eng, log), ReadHeaderTimeout: 10 * time.Second, } ln, err := net.Listen("tcp", listen) if err != nil { return err } log.Info("sim-engine dinliyor", "addr", ln.Addr().String(), "model", cfg.Model, "max_num_seqs", cfg.MaxNumSeqs, "num_gpu_blocks", cfg.NumGPUBlocks, "prefix_cache_blocks", cfg.PrefixCacheBlocks, ) ctx, stop := signal.NotifyContext(cmd.Context(), syscall.SIGINT, syscall.SIGTERM) defer stop() errCh := make(chan error, 1) go func() { errCh <- srv.Serve(ln) }() select { case err := <-errCh: if errors.Is(err, http.ErrServerClosed) { return nil } return err case <-ctx.Done(): log.Info("kapanıyor") shutCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() return srv.Shutdown(shutCtx) } }, } f := cmd.Flags() f.StringVar(&listen, "listen", ":8000", "dinlenecek adres") f.StringVar(&cfg.Model, "model", cfg.Model, "sunulan model adı") f.IntVar(&cfg.MaxNumSeqs, "max-num-seqs", cfg.MaxNumSeqs, "eşzamanlı dizi sayısı (batch kapasitesi)") f.IntVar(&cfg.BlockSize, "block-size", cfg.BlockSize, "KV blok başına token") f.IntVar(&cfg.NumGPUBlocks, "num-gpu-blocks", cfg.NumGPUBlocks, "toplam KV cache bloğu") f.IntVar(&cfg.PrefixCacheBlocks, "prefix-cache-blocks", cfg.PrefixCacheBlocks, "prefix cache blok kapasitesi (0=kapalı)") f.Float64Var(&cfg.PrefillTokensPerSec, "prefill-tps", cfg.PrefillTokensPerSec, "prefill hızı (token/sn, engine geneli)") f.Float64Var(&cfg.DecodeTokensPerSec, "decode-tps", cfg.DecodeTokensPerSec, "tek dizi decode hızı (token/sn)") f.Float64Var(&cfg.BatchContention, "batch-contention", cfg.BatchContention, "batch'teki her ek dizinin yavaşlatma katsayısı") f.IntVar(&cfg.DefaultOutputTokens, "default-output-tokens", cfg.DefaultOutputTokens, "max_tokens verilmezse üretilecek token") f.DurationVar(&cfg.Tick, "tick", cfg.Tick, "simülasyon adımı") f.Float64Var(&cfg.FailRate, "fail-rate", 0, "isteklerin yapay hata oranı (kaos testi)") f.Int64Var(&cfg.Seed, "seed", 0, "rastgelelik tohumu (0=zaman)") return cmd }