Skip to content

Commit 1a6b385

Browse files
committed
fix: fix the issue which the server-side did not report failure after a panic occurred during request processing
1 parent c50055a commit 1a6b385

File tree

3 files changed

+69
-9
lines changed

3 files changed

+69
-9
lines changed

pkg/remote/trans/default_server_handler.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,11 @@ func (t *svrTransHandler) OnRead(ctx context.Context, conn net.Conn) (err error)
144144
} else {
145145
klog.CtxErrorf(ctx, "KITEX: panic happened, error=%v\nstack=%s", panicErr, stack)
146146
}
147-
if err != nil {
148-
wrapErr = kerrors.ErrPanic.WithCauseAndStack(fmt.Errorf("[happened in OnRead] %s, last error=%s", panicErr, err.Error()), stack)
149-
} else {
147+
if err == nil {
148+
// if err is nil, set err as panic wrapErr
150149
wrapErr = kerrors.ErrPanic.WithCauseAndStack(fmt.Errorf("[happened in OnRead] %s", panicErr), stack)
150+
err = remote.NewTransError(remote.InternalError, wrapErr)
151+
t.writeErrorReplyIfNeeded(ctx, recvMsg, conn, err, ri, true)
151152
}
152153
}
153154
t.finishTracer(ctx, ri, err, panicErr)
@@ -158,10 +159,9 @@ func (t *svrTransHandler) OnRead(ctx context.Context, conn net.Conn) (err error)
158159
if rpcinfo.PoolEnabled() {
159160
t.opt.InitOrResetRPCInfoFunc(ri, conn.RemoteAddr())
160161
}
161-
if wrapErr != nil {
162-
err = wrapErr
163-
}
164162
if err != nil && !closeConnOutsideIfErr {
163+
// when error is not nil, outside will close conn,
164+
// set err not nil just indicate that this kind of error don't need close conn
165165
err = nil
166166
}
167167
}()
@@ -186,7 +186,7 @@ func (t *svrTransHandler) OnRead(ctx context.Context, conn net.Conn) (err error)
186186
// reply processing
187187
var methodInfo serviceinfo.MethodInfo
188188
if methodInfo, err = GetMethodInfo(ri, svcInfo); err != nil {
189-
// it won't be err, because the method has been checked in decode, err check here just do defensive inspection
189+
// it won't be error, because the method has been checked in decode, err check here just do defensive inspection
190190
t.writeErrorReplyIfNeeded(ctx, recvMsg, conn, err, ri, true)
191191
// for proxy case, need read actual remoteAddr, error print must exec after writeErrorReplyIfNeeded,
192192
// t.OnError(ctx, err, conn) will be executed at outer function when transServer close the conn
@@ -278,6 +278,12 @@ func (t *svrTransHandler) writeErrorReplyIfNeeded(
278278
// conn is closed, no need reply
279279
return
280280
}
281+
defer func() {
282+
if r := recover(); r != nil {
283+
rService, rAddr := getRemoteInfo(ri, conn)
284+
klog.CtxErrorf(ctx, "KITEX: write error reply panic, remoteAddress=%s, remoteService=%s, error=%v\nstack=%s", rAddr, rService, r, string(debug.Stack()))
285+
}
286+
}()
281287
svcInfo := recvMsg.ServiceInfo()
282288
if svcInfo != nil {
283289
if methodInfo, _ := GetMethodInfo(ri, svcInfo); methodInfo != nil {

pkg/remote/trans/default_server_handler_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"context"
2121
"errors"
2222
"net"
23+
"strings"
2324
"testing"
2425

2526
"github.com/golang/mock/gomock"
@@ -211,6 +212,59 @@ func TestSvrTransHandlerReadErr(t *testing.T) {
211212
test.Assert(t, errors.Is(err, mockErr))
212213
}
213214

215+
func TestSvrTransHandlerReadPanic(t *testing.T) {
216+
ctrl := gomock.NewController(t)
217+
defer ctrl.Finish()
218+
219+
mockTracer := stats.NewMockTracer(ctrl)
220+
mockTracer.EXPECT().Start(gomock.Any()).DoAndReturn(func(ctx context.Context) context.Context { return ctx }).AnyTimes()
221+
mockTracer.EXPECT().Finish(gomock.Any()).DoAndReturn(func(ctx context.Context) {
222+
err := rpcinfo.GetRPCInfo(ctx).Stats().Error()
223+
test.Assert(t, err != nil)
224+
}).AnyTimes()
225+
226+
buf := remote.NewReaderWriterBuffer(1024)
227+
ext := &MockExtension{
228+
NewWriteByteBufferFunc: func(ctx context.Context, conn net.Conn, msg remote.Message) remote.ByteBuffer {
229+
return buf
230+
},
231+
NewReadByteBufferFunc: func(ctx context.Context, conn net.Conn, msg remote.Message) remote.ByteBuffer {
232+
return buf
233+
},
234+
}
235+
236+
tracerCtl := &rpcinfo.TraceController{}
237+
tracerCtl.Append(mockTracer)
238+
opt := &remote.ServerOption{
239+
Codec: &MockCodec{
240+
EncodeFunc: func(ctx context.Context, msg remote.Message, out remote.ByteBuffer) error {
241+
return nil
242+
},
243+
DecodeFunc: func(ctx context.Context, msg remote.Message, in remote.ByteBuffer) error {
244+
panic("mock")
245+
},
246+
},
247+
SvcSearcher: svcSearcher,
248+
TargetSvcInfo: svcInfo,
249+
TracerCtl: tracerCtl,
250+
InitOrResetRPCInfoFunc: func(ri rpcinfo.RPCInfo, addr net.Addr) rpcinfo.RPCInfo {
251+
rpcinfo.AsMutableEndpointInfo(ri.From()).SetAddress(addr)
252+
return ri
253+
},
254+
}
255+
ri := rpcinfo.NewRPCInfo(rpcinfo.EmptyEndpointInfo(), rpcinfo.FromBasicInfo(&rpcinfo.EndpointBasicInfo{}),
256+
rpcinfo.NewInvocation("", ""), nil, rpcinfo.NewRPCStats())
257+
ctx := rpcinfo.NewCtxWithRPCInfo(context.Background(), ri)
258+
259+
svrHandler, err := NewDefaultSvrTransHandler(opt, ext)
260+
test.Assert(t, err == nil)
261+
pl := remote.NewTransPipeline(svrHandler)
262+
svrHandler.SetPipeline(pl)
263+
err = svrHandler.OnRead(ctx, &mocks.Conn{})
264+
test.Assert(t, err != nil)
265+
test.Assert(t, strings.Contains(err.Error(), "panic"))
266+
}
267+
214268
func TestSvrTransHandlerOnReadHeartbeat(t *testing.T) {
215269
ctrl := gomock.NewController(t)
216270
defer ctrl.Finish()

pkg/remote/trans/netpoll/server_handler_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,8 @@ func TestInvokeErr(t *testing.T) {
172172
test.Assert(t, isInvoked)
173173
}
174174

175-
// TestPanicAfterRead test server_handler not panic after read
176-
func TestPanicAfterRead(t *testing.T) {
175+
// TestPipelineNilPanic test server_handler that TransPipeline is nil
176+
func TestPipelineNilPanic(t *testing.T) {
177177
// 1. prepare mock data
178178
var isWriteBufFlushed bool
179179
var isReaderBufReleased bool

0 commit comments

Comments
 (0)