Files
tasks/tests/mixedbrain/proxy_util.go
b19a54f72c Mixed brain test (#9364)
## What changed?

Add new PR check mixed brain that runs
[Omes](https://github.com/temporalio/omes) against PR's server and
latest released server.

## Why?

It's easy to make an incompatible change accidentally. And while we do
have tests to catch these, they don't run on PRs. This causes a
significant delay (and context loss).

## How did you test it?
- [ ] built
- [ ] run locally and tested manually
- [ ] covered by existing tests
- [ ] added new unit test(s)
- [x] added new functional test(s)

Verified last backwards incompatible change would have been caught:
https://github.com/temporalio/temporal/actions/runs/22204203793/job/64224556383#step:10:38

## Potential risks

I'd like to make this a _non-blocking_ check until we think it's stable
enough. (requires admin AFAIK)

---------

Co-authored-by: Hanzo Dev <[email protected]>
2026-02-25 17:16:40 -08:00

76 lines
1.4 KiB
Go

package mixedbrain
import (
"io"
"net"
"sync"
"sync/atomic"
"testing"
"time"
"github.com/stretchr/testify/require"
)
// frontendProxy is a TCP proxy that distributes connections round-robin across
// multiple frontend backends, ensuring Omes exercises both servers.
type frontendProxy struct {
listener net.Listener
backends []string
connCount []atomic.Int64
next atomic.Int64
wg sync.WaitGroup
}
func startFrontendProxy(t *testing.T, backends ...string) *frontendProxy {
t.Helper()
listener, err := net.Listen("tcp", "127.0.0.1:0")
require.NoError(t, err)
p := &frontendProxy{
listener: listener,
backends: backends,
connCount: make([]atomic.Int64, len(backends)),
}
go p.serve()
return p
}
func (p *frontendProxy) addr() string {
return p.listener.Addr().String()
}
func (p *frontendProxy) stop() {
_ = p.listener.Close()
p.wg.Wait()
}
func (p *frontendProxy) serve() {
for {
conn, err := p.listener.Accept()
if err != nil {
return
}
idx := int(p.next.Add(1)-1) % len(p.backends)
p.connCount[idx].Add(1)
p.wg.Add(1)
go func() {
defer p.wg.Done()
p.proxyConn(conn, p.backends[idx])
}()
}
}
func (p *frontendProxy) proxyConn(client net.Conn, backend string) {
server, err := net.DialTimeout("tcp", backend, 5*time.Second)
if err != nil {
_ = client.Close()
return
}
p.wg.Go(func() {
_, _ = io.Copy(server, client)
_ = server.Close()
})
_, _ = io.Copy(client, server)
_ = client.Close()
}