Skip to content
quarry Artifact [72d2f14556]
Login

Artifact [72d2f14556]

Artifact 72d2f145562e43d4d3bb43f0d1ef5feab6de0070f576a33fd58cc0faccec6208:


package events

import (
	"fmt"
	"os"
	"testing"
	"time"

	"github.com/nats-io/nats.go"
)

// Where does ingest time actually go? Compare sync publish (what watch()
// does today) against async batched publish, same payload shape.
//
// This MEASURES rather than asserts, so it is opt-in: it would otherwise
// add seconds to every run and report a number nobody reads. Run it with
//
//	QUARRY_BENCH=1 go test ./internal/events -run PublishThroughput -v
//
// It is kept because of what it settled on 2026-08-16: the hypothesis
// that synchronous publish was the ingest bottleneck was WRONG — sync
// managed 46,700 msg/s, about a second for a 41k-artifact store. The
// real cost was elsewhere (zit frames, and quarry's own folding), and
// this is the evidence that redirected the search.
func TestPublishThroughput(t *testing.T) {
	if os.Getenv("QUARRY_BENCH") == "" {
		t.Skip("set QUARRY_BENCH=1 to measure publish throughput")
	}
	ev, err := Start(t.TempDir())
	if err != nil {
		t.Fatal(err)
	}
	defer ev.Close()
	payload := make([]byte, 1200) // a typical parsed-manifest JSON
	const n = 3000

	start := time.Now()
	for i := 0; i < n; i++ {
		if _, err := ev.JS().Publish("zit.evt.bench.artifact", payload); err != nil {
			t.Fatal(err)
		}
	}
	sync := time.Since(start)

	start = time.Now()
	var last nats.PubAckFuture
	for i := 0; i < n; i++ {
		f, err := ev.JS().PublishAsync("zit.evt.bench2.artifact", payload)
		if err != nil {
			t.Fatal(err)
		}
		last = f
	}
	select {
	case <-ev.JS().PublishAsyncComplete():
	case <-time.After(30 * time.Second):
		t.Fatal("async publish did not drain")
	}
	_ = last
	async := time.Since(start)

	fmt.Printf("\n  sync : %v for %d msgs = %.0f msg/s\n", sync.Round(time.Millisecond), n, float64(n)/sync.Seconds())
	fmt.Printf("  async: %v for %d msgs = %.0f msg/s  (%.1fx faster)\n\n",
		async.Round(time.Millisecond), n, float64(n)/async.Seconds(), sync.Seconds()/async.Seconds())
}