I’m new to go and I’m trying to understand why the following code doesn’t work. I have a context with a timeout and I am doing a for loop with a select with <-ctx.Done() as the first case. I expected the function to exit when the timeout happens but it doesn’t. Can someone please tell me what I am doing wrong?
The people writing the scheduler tries to make it able to handle cases like this, but it seems like there is a bug and it doesn’t properly track timers or something.
Even when the scheduler is able to solve polling loops it is a huge performance cost so you shouldn’t write this code on purpose.
The problem here is that context was never cancelled. You defer-ed it. Defer means that the function will execute when the func where you defined it exits. Main will never do, since you use infinite loop. To exit from the loop with context, you need to call cancel() without defer.
That was what I was thinking of as well. The original code I had was actually reading some bytes at the default case and would wait for 100 ms for at least one byte. I wrote a mock for the reader using bytes.Buffer and put a 100 ms wait inside the Read to mimic the behavior. It would intermittently fail when running the test suite and always pass on its own. Maybe the 100 ms wait wasn’t enough for Go to be able to process the ctx->Done.
Excellent point. I hadn’t realized that select chooses one at random. I thought the cases were placed in priority. However, the second case does not use a select.
I’m using go version 1.22. I did try it on the playground for both version 1.21 and 1.22 and they both fail. I was running it inside a go test on my Windows machine when I first saw the behavior. However, I’ve run it on my Windows machine as a simple app and that was fine.
Yes, I have tried to debug it. If I put print statements, they show me that done is never called even when the timeout has passed. But if I put a breakpoint in, it always works.