github.com/alibaba/ilogtail/pkg@v0.0.0-20250526110833-c53b480d046c/util/timeout_reader.go (about) 1 // Copyright 2021 iLogtail Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package util 16 17 import ( 18 "bufio" 19 "errors" 20 "fmt" 21 "io" 22 "runtime" 23 "time" 24 ) 25 26 const BufferSize = 4096 27 28 var ErrReaderTimeout = errors.New("timeout") 29 30 type TimeoutReader struct { 31 b *bufio.Reader 32 t time.Duration 33 ch <-chan error 34 } 35 36 func NewTimeoutReader(r io.Reader, to time.Duration) *TimeoutReader { 37 return &TimeoutReader{b: bufio.NewReaderSize(r, BufferSize), t: to} 38 } 39 40 func (r *TimeoutReader) Read(b []byte) (n int, err error) { 41 if r.ch == nil { 42 if r.t < 0 || r.b.Buffered() > 0 { 43 return r.b.Read(b) 44 } 45 ch := make(chan error, 1) 46 r.ch = ch 47 go func() { 48 _, err = r.b.Peek(1) 49 ch <- err 50 }() 51 runtime.Gosched() 52 } 53 if r.t < 0 { 54 err = <-r.ch // Block 55 } else { 56 select { 57 case err = <-r.ch: // Poll 58 default: 59 if r.t == 0 { 60 return 0, ErrReaderTimeout 61 } 62 select { 63 case err = <-r.ch: // Timeout 64 case <-time.After(r.t): 65 return 0, ErrReaderTimeout 66 } 67 } 68 } 69 r.ch = nil 70 if r.b.Buffered() > 0 { 71 n, _ = r.b.Read(b) 72 } 73 return 74 } 75 76 func DoFuncWithTimeout(timeout time.Duration, workFunc func() error) error { 77 ch := make(chan error, 1) 78 go func() { 79 ch <- workFunc() 80 }() 81 select { 82 case err := <-ch: 83 return err 84 case <-time.After(timeout): 85 return fmt.Errorf("operation timed out after %v", timeout) 86 } 87 }