@@ -18,6 +18,9 @@ import (
1818	"strings" 
1919	"time" 
2020
21+ 	"github.com/onflow/flow-go/module/component" 
22+ 	"github.com/onflow/flow-go/module/irrecoverable" 
23+ 
2124	gethVM "github.com/onflow/go-ethereum/core/vm" 
2225	gethLog "github.com/onflow/go-ethereum/log" 
2326	"github.com/onflow/go-ethereum/rpc" 
@@ -55,8 +58,12 @@ type Server struct {
5558
5659	config     config.Config 
5760	collector  metrics.Collector 
61+ 
62+ 	startupCompleted  chan  struct {}
5863}
5964
65+ var  _  component.Component  =  (* Server )(nil )
66+ 
6067const  (
6168	shutdownTimeout       =  5  *  time .Second 
6269	batchRequestLimit     =  50 
@@ -77,10 +84,11 @@ func NewServer(
7784	gethLog .SetDefault (gethLog .NewLogger (zeroSlog ))
7885
7986	return  & Server {
80- 		logger :    logger ,
81- 		timeouts :  rpc .DefaultHTTPTimeouts ,
82- 		config :    cfg ,
83- 		collector : collector ,
87+ 		logger :           logger ,
88+ 		timeouts :         rpc .DefaultHTTPTimeouts ,
89+ 		config :           cfg ,
90+ 		collector :        collector ,
91+ 		startupCompleted : make (chan  struct {}),
8492	}
8593}
8694
@@ -177,9 +185,10 @@ func (h *Server) disableWS() bool {
177185}
178186
179187// Start starts the HTTP server if it is enabled and not already running. 
180- func  (h  * Server ) Start () error  {
188+ func  (h  * Server ) Start (ctx  irrecoverable.SignalerContext ) {
189+ 	defer  close (h .startupCompleted )
181190	if  h .endpoint  ==  ""  ||  h .listener  !=  nil  {
182- 		return  nil   // already running or not configured 
191+ 		return  // already running or not configured 
183192	}
184193
185194	// Initialize the server. 
@@ -190,16 +199,21 @@ func (h *Server) Start() error {
190199		h .server .ReadHeaderTimeout  =  h .timeouts .ReadHeaderTimeout 
191200		h .server .WriteTimeout  =  h .timeouts .WriteTimeout 
192201		h .server .IdleTimeout  =  h .timeouts .IdleTimeout 
202+ 		h .server .BaseContext  =  func (_  net.Listener ) context.Context  {
203+ 			return  ctx 
204+ 		}
193205	}
194206
207+ 	listenConfig  :=  net.ListenConfig {}
195208	// Start the server. 
196- 	listener , err  :=  net .Listen ("tcp" , h .endpoint )
209+ 	listener , err  :=  listenConfig .Listen (ctx ,  "tcp" , h .endpoint )
197210	if  err  !=  nil  {
198211		// If the server fails to start, we need to clear out the RPC and WS 
199212		// configurations so they can be configured another time. 
200213		h .disableRPC ()
201214		h .disableWS ()
202- 		return  err 
215+ 		ctx .Throw (err )
216+ 		return 
203217	}
204218
205219	h .listener  =  listener 
@@ -211,7 +225,7 @@ func (h *Server) Start() error {
211225				return 
212226			}
213227			h .logger .Err (err ).Msg ("failed to start API server" )
214- 			panic (err )
228+ 			ctx . Throw (err )
215229		}
216230	}()
217231
@@ -223,8 +237,17 @@ func (h *Server) Start() error {
223237		url  :=  fmt .Sprintf ("ws://%v" , listener .Addr ())
224238		h .logger .Info ().Msgf ("JSON-RPC over WebSocket enabled: %s" , url )
225239	}
240+ }
226241
227- 	return  nil 
242+ func  (h  * Server ) Ready () <- chan  struct {} {
243+ 	ready  :=  make (chan  struct {})
244+ 
245+ 	go  func () {
246+ 		<- h .startupCompleted 
247+ 		close (ready )
248+ 	}()
249+ 
250+ 	return  ready 
228251}
229252
230253// disableRPC stops the JSON-RPC over HTTP handler. 
@@ -294,41 +317,50 @@ func (h *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
294317	w .WriteHeader (http .StatusNotFound )
295318}
296319
297- // Stop shuts down the HTTP server. 
298- func  (h  * Server ) Stop () {
299- 	if  h .listener  ==  nil  {
300- 		return  // not running 
301- 	}
320+ // Done shuts down the HTTP server. 
321+ func  (h  * Server ) Done () <- chan  struct {} {
322+ 	done  :=  make (chan  struct {})
302323
303- 	// Shut down the server. 
304- 	httpHandler  :=  h .httpHandler 
305- 	if  httpHandler  !=  nil  {
306- 		httpHandler .server .Stop ()
307- 		h .httpHandler  =  nil 
308- 	}
324+ 	go  func () {
325+ 		defer  close (done )
309326
310- 	wsHandler  :=  h .wsHandler 
311- 	if  wsHandler  !=  nil  {
312- 		wsHandler .server .Stop ()
313- 		h .wsHandler  =  nil 
314- 	}
327+ 		if  h .listener  ==  nil  {
328+ 			return  // not running 
329+ 		}
315330
316- 	ctx , cancel  :=  context .WithTimeout (context .Background (), shutdownTimeout )
317- 	defer  cancel ()
318- 	err  :=  h .server .Shutdown (ctx )
319- 	if  err  !=  nil  &&  err  ==  ctx .Err () {
320- 		h .logger .Warn ().Msg ("HTTP server graceful shutdown timed out" )
321- 		h .server .Close ()
322- 	}
331+ 		// Shut down the server. 
332+ 		httpHandler  :=  h .httpHandler 
333+ 		if  httpHandler  !=  nil  {
334+ 			httpHandler .server .Stop ()
335+ 			h .httpHandler  =  nil 
336+ 		}
337+ 
338+ 		wsHandler  :=  h .wsHandler 
339+ 		if  wsHandler  !=  nil  {
340+ 			wsHandler .server .Stop ()
341+ 			h .wsHandler  =  nil 
342+ 		}
343+ 
344+ 		ctx , cancel  :=  context .WithTimeout (context .Background (), shutdownTimeout )
345+ 		defer  cancel ()
346+ 		err  :=  h .server .Shutdown (ctx )
347+ 		if  err  !=  nil  &&  err  ==  ctx .Err () {
348+ 			h .logger .Warn ().Msg ("HTTP server graceful shutdown timed out" )
349+ 			h .server .Close ()
350+ 		}
323351
324- 	h .listener .Close ()
325- 	h .logger .Info ().Msgf (
326- 		"HTTP server stopped, endpoint: %s" , h .listener .Addr (),
327- 	)
352+ 		h .listener .Close ()
353+ 		h .logger .Info ().Msgf (
354+ 			"HTTP server stopped, endpoint: %s" , h .listener .Addr (),
355+ 		)
356+ 
357+ 		// Clear out everything to allow re-configuring it later. 
358+ 		h .host , h .port , h .endpoint  =  "" , 0 , "" 
359+ 		h .server , h .listener  =  nil , nil 
360+ 
361+ 	}()
328362
329- 	// Clear out everything to allow re-configuring it later. 
330- 	h .host , h .port , h .endpoint  =  "" , 0 , "" 
331- 	h .server , h .listener  =  nil , nil 
363+ 	return  done 
332364}
333365
334366// CheckTimeouts ensures that timeout values are meaningful 
0 commit comments