Skip to content

fix(go/genkit): add port number to runtime file name #3168

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 40 additions & 9 deletions go/genkit/reflection.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,51 @@ type reflectionServer struct {
RuntimeFilePath string // Path to the runtime file that was written at startup.
}

// startReflectionServer starts the Reflection API server listening at the
// value of the environment variable GENKIT_REFLECTION_PORT for the port,
// or ":3100" if it is empty.
// findAvailablePort finds an available TCP port starting from a given port.
// It checks up to 100 ports.
func findAvailablePort(startPort int) (int, error) {
for port := startPort; port < startPort+100; port++ {
addr := fmt.Sprintf("127.0.0.1:%d", port)
if l, err := net.Listen("tcp", addr); err == nil {
l.Close()
return port, nil
}
}
return -1, fmt.Errorf("no available port in range %d-%d", startPort, startPort+99)
}

// startReflectionServer starts the Reflection API server. If the
// GENKIT_REFLECTION_PORT environment variable is set, it will listen on that
// port. Otherwise, it searches for an available port starting at 3100.
func startReflectionServer(ctx context.Context, g *Genkit, errCh chan<- error, serverStartCh chan<- struct{}) *reflectionServer {
if g == nil {
errCh <- fmt.Errorf("nil Genkit provided")
return nil
}

addr := "127.0.0.1:3100"
if os.Getenv("GENKIT_REFLECTION_PORT") != "" {
addr = "127.0.0.1:" + os.Getenv("GENKIT_REFLECTION_PORT")
var port int
var err error
if portStr := os.Getenv("GENKIT_REFLECTION_PORT"); portStr != "" {
p, err := strconv.Atoi(portStr)
if err != nil {
errCh <- fmt.Errorf("invalid GENKIT_REFLECTION_PORT: %w", err)
return nil
}
port = p
} else {
startPort := 3100
port, err = findAvailablePort(startPort)
if err != nil {
errCh <- fmt.Errorf("failed to find available port: %w", err)
return nil
}
if port != startPort {
slog.Warn(fmt.Sprintf("Port %d is already in use, using next available port %d instead.", startPort, port))
}
}

addr := fmt.Sprintf("127.0.0.1:%d", port)

s := &reflectionServer{
Server: &http.Server{
Addr: addr,
Expand All @@ -78,7 +109,7 @@ func startReflectionServer(ctx context.Context, g *Genkit, errCh chan<- error, s

slog.Debug("starting reflection server", "addr", s.Addr)

if err := s.writeRuntimeFile(s.Addr); err != nil {
if err := s.writeRuntimeFile(s.Addr, port); err != nil {
errCh <- fmt.Errorf("failed to write runtime file: %w", err)
return nil
}
Expand Down Expand Up @@ -126,7 +157,7 @@ func startReflectionServer(ctx context.Context, g *Genkit, errCh chan<- error, s
}

// writeRuntimeFile writes a file describing the runtime to the project root.
func (s *reflectionServer) writeRuntimeFile(url string) error {
func (s *reflectionServer) writeRuntimeFile(url string, port int) error {
projectRoot, err := findProjectRoot()
if err != nil {
return fmt.Errorf("failed to find project root: %w", err)
Expand All @@ -146,7 +177,7 @@ func (s *reflectionServer) writeRuntimeFile(url string) error {
// remove colons to avoid problems with different OS file name restrictions
timestamp = strings.ReplaceAll(timestamp, ":", "_")

s.RuntimeFilePath = filepath.Join(runtimesDir, fmt.Sprintf("%d-%s.json", os.Getpid(), timestamp))
s.RuntimeFilePath = filepath.Join(runtimesDir, fmt.Sprintf("%d-%d-%s.json", os.Getpid(), port, timestamp))

data := runtimeFileData{
ID: runtimeID,
Expand Down
Loading