I'm not sure what you mean. There's
always going to be a race condition between ctx.Done and thingCh, just depending on whether there's data available. This race condition is unavoidable.
I guess you're thinking of "what if thingCh and ctx.Done activate simultaneously?"
There's no real difference between happening simultaneously and happening one after another.
As for your other point, you can just write code like
select {
case x := <-conditionA:
return x
default:
}
select {
case x := <-conditionB:
return x
default:
}
...
But I've personally never needed code like this.