// to avoid writer block after ctx done, you should close writer after ctx done
//
// call Close() after writer fin
-func WithCtxTO(ctx context.Context, callTree string, to time.Duration, w []io.Writer, r io.Reader, panicf ...func(s string)) io.ReadWriteCloser {
+func WithCtxTO(ctx context.Context, callTree string, to time.Duration, w io.Writer, r io.Reader, panicf ...func(s string)) io.ReadWriteCloser {
var chanw atomic.Int64
chanw.Store(time.Now().Unix())
if len(panicf) == 0 {
case <-ctx.Done():
err = context.Canceled
default:
- for i := 0; i < len(w); i++ {
- _, err = w[i].Write(p)
- }
+ _, err = w.Write(p)
chanw.Store(time.Now().Unix())
}
return
// to avoid writer block after ctx done, you should close writer after ctx done
//
// call Close() after writer fin
-func WithCtxCopy(ctx context.Context, callTree string, to time.Duration, w []io.Writer, r io.Reader, panicf ...func(s string)) error {
+func WithCtxCopy(ctx context.Context, callTree string, to time.Duration, w io.Writer, r io.Reader, panicf ...func(s string)) error {
rwc := WithCtxTO(ctx, callTree, to, w, r, panicf...)
defer rwc.Close()
for buf := make([]byte, 2048); true; {
var panicf = func(s string) {
err = errors.Join(err, errors.New(s))
}
- err = errors.Join(err, pio.WithCtxCopy(req.Context(), t.callTree, time.Duration(int(time.Millisecond)*writeLoopTO), ws, resReadCloser, panicf))
+ err = errors.Join(err, pio.WithCtxCopy(req.Context(), t.callTree, time.Duration(int(time.Millisecond)*writeLoopTO), io.MultiWriter(ws...), resReadCloser, panicf))
resp.Body.Close()
m.Store("/to", func(w http.ResponseWriter, r *http.Request) {
rwc := pio.WithCtxTO(r.Context(), fmt.Sprintf("server handle %v by %v ", r.URL.Path, r.RemoteAddr), time.Second,
- []io.Writer{w}, r.Body, func(s string) {
+ w, r.Body, func(s string) {
fmt.Println(s)
if !strings.Contains(s, "write blocking after rw 2s > 1s, goruntime leak") {
t.Fatal(s)