From 8495cf42b6cca626ab5360adcaec37e0e0495fa3 Mon Sep 17 00:00:00 2001 From: Yevgeniy Miretskiy Date: Fri, 5 Jun 2026 07:24:33 -0400 Subject: [PATCH] s3api: add WithOnListen option for server readiness notification WithOnListen registers a callback invoked once the server is bound and ready to accept connections. It wraps fiber's existing OnListen hook, which fires immediately before the first connection is served. This allows callers to detect readiness deterministically rather than relying on a fixed sleep or polling a health endpoint. Example use in tests: ready := make(chan struct{}) srv, _ := s3api.New(..., s3api.WithOnListen(func() { close(ready) })) go srv.ServeMultiPort([]string{addr}) <-ready // blocks until the server is accepting connections --- s3api/server.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/s3api/server.go b/s3api/server.go index 84943091..1fcede51 100644 --- a/s3api/server.go +++ b/s3api/server.go @@ -58,6 +58,7 @@ type S3ApiServer struct { routes []routeMount middlewares []middlewareMount socketPerm os.FileMode + onListen func() } type routeMount struct { @@ -328,6 +329,14 @@ func WithDisableACL() Option { return func(s *S3ApiServer) { s.Router.disableACL = true } } +// WithOnListen registers a callback that is invoked once the server is bound +// and ready to accept requests. It is called from the fiber OnListen hook, +// which fires immediately before the server begins serving the first +// connection. Use this instead of a fixed sleep to detect readiness reliably. +func WithOnListen(fn func()) Option { + return func(s *S3ApiServer) { s.onListen = fn } +} + // ServeMultiPort creates listeners for multiple port specifications and serves // on all of them simultaneously. This supports listening on multiple ports and/or // addresses (e.g., [":7070", "localhost:8080", "0.0.0.0:9090"]). @@ -362,6 +371,14 @@ func (sa *S3ApiServer) ServeMultiPort(ports []string) error { // Combine all listeners finalListener := utils.NewMultiListener(listeners...) + if sa.onListen != nil { + fn := sa.onListen + sa.app.Hooks().OnListen(func(fiber.ListenData) error { + fn() + return nil + }) + } + return sa.app.Listener(finalListener) }