@@ -18,6 +18,9 @@ import (
18
18
"strings"
19
19
"time"
20
20
21
+ "github.com/onflow/flow-go/module/component"
22
+ "github.com/onflow/flow-go/module/irrecoverable"
23
+
21
24
gethVM "github.com/onflow/go-ethereum/core/vm"
22
25
gethLog "github.com/onflow/go-ethereum/log"
23
26
"github.com/onflow/go-ethereum/rpc"
@@ -55,8 +58,12 @@ type Server struct {
55
58
56
59
config config.Config
57
60
collector metrics.Collector
61
+
62
+ startupCompleted chan struct {}
58
63
}
59
64
65
+ var _ component.Component = (* Server )(nil )
66
+
60
67
const (
61
68
shutdownTimeout = 5 * time .Second
62
69
batchRequestLimit = 50
@@ -77,10 +84,11 @@ func NewServer(
77
84
gethLog .SetDefault (gethLog .NewLogger (zeroSlog ))
78
85
79
86
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 {}),
84
92
}
85
93
}
86
94
@@ -177,9 +185,10 @@ func (h *Server) disableWS() bool {
177
185
}
178
186
179
187
// 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 )
181
190
if h .endpoint == "" || h .listener != nil {
182
- return nil // already running or not configured
191
+ return // already running or not configured
183
192
}
184
193
185
194
// Initialize the server.
@@ -190,16 +199,21 @@ func (h *Server) Start() error {
190
199
h .server .ReadHeaderTimeout = h .timeouts .ReadHeaderTimeout
191
200
h .server .WriteTimeout = h .timeouts .WriteTimeout
192
201
h .server .IdleTimeout = h .timeouts .IdleTimeout
202
+ h .server .BaseContext = func (_ net.Listener ) context.Context {
203
+ return ctx
204
+ }
193
205
}
194
206
207
+ listenConfig := net.ListenConfig {}
195
208
// Start the server.
196
- listener , err := net .Listen ("tcp" , h .endpoint )
209
+ listener , err := listenConfig .Listen (ctx , "tcp" , h .endpoint )
197
210
if err != nil {
198
211
// If the server fails to start, we need to clear out the RPC and WS
199
212
// configurations so they can be configured another time.
200
213
h .disableRPC ()
201
214
h .disableWS ()
202
- return err
215
+ ctx .Throw (err )
216
+ return
203
217
}
204
218
205
219
h .listener = listener
@@ -211,7 +225,7 @@ func (h *Server) Start() error {
211
225
return
212
226
}
213
227
h .logger .Err (err ).Msg ("failed to start API server" )
214
- panic (err )
228
+ ctx . Throw (err )
215
229
}
216
230
}()
217
231
@@ -223,8 +237,17 @@ func (h *Server) Start() error {
223
237
url := fmt .Sprintf ("ws://%v" , listener .Addr ())
224
238
h .logger .Info ().Msgf ("JSON-RPC over WebSocket enabled: %s" , url )
225
239
}
240
+ }
226
241
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
228
251
}
229
252
230
253
// disableRPC stops the JSON-RPC over HTTP handler.
@@ -294,41 +317,50 @@ func (h *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
294
317
w .WriteHeader (http .StatusNotFound )
295
318
}
296
319
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 {})
302
323
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 )
309
326
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
+ }
315
330
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
+ }
323
351
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
+ }()
328
362
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
332
364
}
333
365
334
366
// CheckTimeouts ensures that timeout values are meaningful
0 commit comments