php editor Xinyi will introduce how to use timeout and retry to create context in Go language. When writing code, we often encounter situations where we need to limit the execution time of an operation or retry when the operation fails. Go language provides a simple and powerful mechanism, context, which can help us achieve these needs. By properly utilizing timeouts and retry mechanisms, we can improve the reliability and stability of the code while improving the user experience. In the next article, we will discuss in detail how to use timeouts and retries to create context in Go language.
I try to create context in go using timeout and multiple retries. Here is the code sample
func readretry(port io.readwritecloser, timeout, cnt int) []byte { fmt.println("in read retry") for i := 0; i < cnt; i++ { fmt.println("read attempt:", i) res := readwithcontext(timeout, port) if res != nil { return res } } return nil } func readwithcontext(timeout int, port io.readwritecloser) []byte { fmt.println("in readwithcontext") fmt.println("opening channel") rcvch := make(chan []byte) ctx, cancel := context.withtimeout(context.background(), time.duration(time.second*time.duration(timeout))) defer cancel() go reader(ctx, port, rcvch) for { select { case <-ctx.done(): fmt.println("reader: context cancelled") return nil case buf := <-rcvch: fmt.println("reader: got data") return buf } } } func reader(ctx context.context, port io.readwritecloser, rcvch chan []byte) { fmt.println("in reader") answ := make([]byte, 1024) buf := bytes.buffer{} var err error for { i := 0 i, err = port.read(answ) if err != nil && err != io.eof { log.printf("port.read: %v", err) } if i != 0 { answ = answ[:i] buf.write(answ) if buf.bytes()[len(buf.bytes())-1] == delimiter { fmt.print("received: ") printbuf(buf.bytes()) rcvch <- buf.bytes() //if there is no data in the first attempt, cannot write to the channel here!! return } } } }
Then, I call readretry result := readretry(port, 2, 5) // 2 second timeout, 5 retries. But if the data is not ready for the first time, then reader cannot write to rcvch. Maybe it’s full? Why? If I try to close the channel at the end of readwithcontext execution, a conflict occurs - writing to a closed channel. Where is the collision? It believes that readwithcontext will be started as a new instance every time, creating a new instance of rcvch. If reader is closed due to timeout, all chain functions and Its local variables (including channels) have been destroyed. However, it seems I made a mistake. So, how to retry? See what the log looks like:
IN READ RETRY Read attempt: 1 IN readWithContext Opening channel IN reader Start reader Received: 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0d //<- data is received, but not written to the channel!! reader: context cancelled
Each retry will create a new reader and a new channel. If readWithContext
times out, the reader is still there waiting, and may eventually read, but now no one is listening on the other end of the channel, so the reader is leaked.
Have a reader
goroutine and a channel, use readWithContext
to read from it. You must also stop the reader if the context expires and all retries are exhausted.
The above is the detailed content of How to create context using timeouts and retries in Go?. For more information, please follow other related articles on the PHP Chinese website!