Skip to content

Commit 1018bf6

Browse files
karalabefjl
authored andcommitted
rpc: honour pending requests before tearing conn down (ethereum#3814)
1 parent 37e2525 commit 1018bf6

File tree

1 file changed

+28
-14
lines changed

1 file changed

+28
-14
lines changed

rpc/server.go

+28-14
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"fmt"
2222
"reflect"
2323
"runtime"
24+
"sync"
2425
"sync/atomic"
2526

2627
"github.com/ethereum/go-ethereum/log"
@@ -143,14 +144,15 @@ func hasOption(option CodecOption, options []CodecOption) bool {
143144
// requests until the codec returns an error when reading a request (in most cases
144145
// an EOF). It executes requests in parallel when singleShot is false.
145146
func (s *Server) serveRequest(codec ServerCodec, singleShot bool, options CodecOption) error {
147+
var pend sync.WaitGroup
148+
146149
defer func() {
147150
if err := recover(); err != nil {
148151
const size = 64 << 10
149152
buf := make([]byte, size)
150153
buf = buf[:runtime.Stack(buf, false)]
151154
log.Error(fmt.Sprint(string(buf)))
152155
}
153-
154156
s.codecsMu.Lock()
155157
s.codecs.Remove(codec)
156158
s.codecsMu.Unlock()
@@ -179,8 +181,13 @@ func (s *Server) serveRequest(codec ServerCodec, singleShot bool, options CodecO
179181
for atomic.LoadInt32(&s.run) == 1 {
180182
reqs, batch, err := s.readRequest(codec)
181183
if err != nil {
182-
log.Debug(fmt.Sprintf("read error %v\n", err))
183-
codec.Write(codec.CreateErrorResponse(nil, err))
184+
// If a parsing error occurred, send an error
185+
if err.Error() != "EOF" {
186+
log.Debug(fmt.Sprintf("read error %v\n", err))
187+
codec.Write(codec.CreateErrorResponse(nil, err))
188+
}
189+
// Error or end of stream, wait for requests and tear down
190+
pend.Wait()
184191
return nil
185192
}
186193

@@ -199,20 +206,27 @@ func (s *Server) serveRequest(codec ServerCodec, singleShot bool, options CodecO
199206
}
200207
return nil
201208
}
202-
203-
if singleShot && batch {
204-
s.execBatch(ctx, codec, reqs)
205-
return nil
206-
} else if singleShot && !batch {
207-
s.exec(ctx, codec, reqs[0])
209+
// If a single shot request is executing, run and return immediately
210+
if singleShot {
211+
if batch {
212+
s.execBatch(ctx, codec, reqs)
213+
} else {
214+
s.exec(ctx, codec, reqs[0])
215+
}
208216
return nil
209-
} else if !singleShot && batch {
210-
go s.execBatch(ctx, codec, reqs)
211-
} else {
212-
go s.exec(ctx, codec, reqs[0])
213217
}
214-
}
218+
// For multi-shot connections, start a goroutine to serve and loop back
219+
pend.Add(1)
215220

221+
go func(reqs []*serverRequest, batch bool) {
222+
defer pend.Done()
223+
if batch {
224+
s.execBatch(ctx, codec, reqs)
225+
} else {
226+
s.exec(ctx, codec, reqs[0])
227+
}
228+
}(reqs, batch)
229+
}
216230
return nil
217231
}
218232

0 commit comments

Comments
 (0)