I want to set a deadline on client connection, he must do something within the first 10 seconds or else get disconnected, if he does do something, I want to remove the deadline.
// meConn = *TCPConn
c.meConn.SetDeadline(time.Now().Add(10 * time.Second))
But the documentation doesn't say anything about disabling the deadline.
Also, is it safe to keep changing the deadline when a certain condition is met?
To reset the deadline, you can call SetDeadline with a "zero" value as the docs stay. This the "zero" value can be set with:
conn.SetDeadline(time.Time{})
It states:
// SetReadDeadline sets the deadline for future Read calls.
// A zero value for t means Read will not time out.
SetReadDeadline(t time.Time) error
In the documentation for SetReadDeadLine
so you will need to pass in zero when a client sends what you expect.
and the SetDeadLine says it is setting both the reader and the writer, so make sure you also meant to set the writer.
// SetDeadline sets the read and write deadlines associated
// with the connection. It is equivalent to calling both
// SetReadDeadline and SetWriteDeadline.
Related
I'm currently working on migrating our code from global sign package to go mongo-driver, not sure where should I use context.TODO() and context.Background(), it’s really confusing, I know both it returns non-nil empty, so should I use context.Background() in the main function & init() functions? And use context.TODO() in other places? Can anyone help with this?
Trying to check to see which param should I use context.TODO() or context.Background().
Check their documentation:
context.Background():
func Background() Context
Background returns a non-nil, empty Context. It is never canceled, has no values, and has no deadline. It is typically used by the main function, initialization, and tests, and as the top-level Context for incoming requests.
context.TODO():
func TODO() Context
TODO returns a non-nil, empty Context. Code should use context.TODO when it's unclear which Context to use or it is not yet available (because the surrounding function has not yet been extended to accept a Context parameter).
According to the doc, when you need a context but you don't have one (yet) and don't know what to use, use context.TODO(). This is exactly your case, using context.TODO() properly documents this. Also, static analysis tools and IDEs may give support discovering these contexts and give you warning later to address the issue.
Also note that if you do have a context when you have to use the mongo driver, then consider using that context, or deriving a new one from it.
For example, if you are writing an HTTP handler where you need to query some documents, the HTTP request http.Request already has a context which you can access using Request.Context(). This is a prime candidate to use when you call other API functions that require a context.
Why, you may ask? Because the request's context is cancelled when the HTTP client abandons / aborts the request, which means whatever you do, the client will not receive it, so for example if the HTTP handler just serves information, you may as well abort generating it, saving some resources. So if the request context is cancelled while you're executing a MongoDB query, you may as well cancel the query too, because you won't need (won't process) the result anyway. Cancelling the context passed to the query execution (Collection.Find() for example) is the way to tell the MongoDB server to cancel the query if possible (because you won't need the result).
So using the request context in this case can save you some CPU time and memory both on the HTTP server and on the MongoDB server as well.
Another example: let's say you have to produce the HTTP response within 10 seconds (may be a platform limitation), during which you have to execute a MongoDB operation, and you have to post process the results which takes 4 seconds. In this scenario if the MongoDB operation takes more than 6 seconds, you would not be able to complete the post processing to fit in the 10-second limit. So you might as well cancel the MongoDB operation if it doesn't complete in 6 seconds.
An easy way to solve this is to derive a context with 6 seconds timeout:
ctx, cancel := context.WithTimeout(r.Context(), 6 * time.Second)
defer cancel()
// ctx automatically times out after 6 seconds
curs, err := c.Find(ctx, bson.M{"some": "filter"})
In this example ctx will time out after 6 seconds, so if the c.Find() operation doesn't get finished by that, the passed ctx will signal that it can be cancelled (in which case an error will be returned). Since ctx is derived from r.Context(), if the request's context get's cancelled earlier (e.g. the HTTP client aborts), ctx will also be cancelled.
Now let's say you're not writing an HTTP handler but some other code (standalone app, background worker etc.), where you may not have a context, but you have your standards that you don't want to wait more than 30 seconds for a query. This is a prime example where you may derive a context from context.Background() using a 30-sec timeout:
ctx, cancel := context.WithTimeout(context.Background(), 30 * time.Second)
defer cancel()
// ctx automatically times out after 30 seconds
curs, err := c.Find(ctx, bson.M{"some": "filter"})
If the query finishes within 30 seconds, all good, you may use the results. If not, the context gets cancelled after 30 sec, and so c.Find() will also (likely) return an error.
context.TODO:
Code should use context.TODO when it's unclear which Context to use or it is not yet available (because the surrounding function has not yet been extended to accept a Context parameter).
context.Background:
Background returns a non-nil, empty Context. It is never canceled, has no values, and has no deadline. It is typically used by the main function, initialization, and tests, and as the top-level Context for incoming requests.
TODO is a placeholder to make it clear that the code should be updated with a more appropriate context in the future, but none is available yet. Background is used when such an indication isn't necessary and you simply need an empty root context with no values or cancellation. The values they return are identical; the only difference is semantic, in that one might scan code for TODO contexts (or use a linter to do so) as places that need to be updated/addressed.
This page on a Go Tutorial about channels seems to be missing a word(s) or was just not edited. I can't tell what it is supposed to say about sending and receiving through channels.
By default, sends and receives block until the other side is ready.
Is a block something within Go? I haven't seen it before. Is block being used as a noun?
I tried searching for clarification. The only other page that has similar wording is educative.io
Moreover, by default, channels send and receive until the other side is ready
But it doesn't make sense. Do they mean:
Channels send and receive regardless of whether or not the other side is ready? Doesn't this seem wasteful?
Or is "don't" missing in the statement above?
"Block" means that the goroutine will wait. You could write it this way:
By default, sends and receives wait until the other side is ready.
"Block" is just the normal term for this. It is not specific to Go. It is possible to use a channel in Go in a non-blocking manner:
You can create a channel with a buffer. As long as there is space in the buffer, a write is non-blocking (but it will block if the buffer is full). As long as there is data in the buffer, a read is non-blocking (but it will block if the buffer is empty).
You can use a select statement with a default branch.
var readch chan int
var writech chan int
var value int
select {
case n := <- readch:
// Received data.
case writech <- value:
// Sent data.
default:
// Didn't send or receive data.
}
In this code, instead of blocking (waiting), the goroutine will go to the default branch.
I am using buffio.Writer in GoLang as follows.
conn, err := net.Dial("tcp", address) // address is of form ip:port
w := bufio.NewWriter(conn)
w.WriteByte(code) // code is a byte
w.Write(data) // data is a byte buffer
w.Flush()
I am trying to modify the above code so that the write() events have a deadline: when the deadline is passed, the write() event will return irrespective of the fact that it was successful or not.
In GoLang its possible to have a deadline, if the conn (connection object) is directly used for writing using conn.SetWriteDeadline(time.Now().Add(n * time.Second)). However, when I use bufifo.writer object, which is essentially a wrapper around conn for buffered IO, there is no API to set a deadline.
While its possible to use conn.SetWriteDeadline(time.Now().Add(n * time.Second)) and use conn.Write(b), its very inefficient since it doesn't buffer the write events (thus a lot of context switches)
Is there a way in GoLang where I can use buffered IO with a writeDeadline()?
Thanks
There are two cases to note here.
If you want to have per write() deadline, then its not possible to use buffering. When you use buffering, then the actual write() is triggered when the buffer is full. So technically its not possible to know when your write() is completed. In this case, you are essentially using conn.write() and you can use conn.SetWriteDeadline(time.Now().Add(n * time.Second)).
In the second case, as #icza has mentioned in the comment, you can set the deadline in the underlying conn object, and the buffio.writer() wrapper will adhere to this rule. While this is semantically correct, it doesn't provide the networking abstraction you want.
Go's websockets have a SetWriteDeadline() function to set the connection's network write deadline. Do I need to set it before every data sending or it can be done just once when the connection is created?
For it to be useful at all, set it every time. Note that it takes a time.Time, not a time.Duration:
SetWriteDeadline(t time.Time) error
Set it once.
PS I checked it myself, it's a simple code.
How do I check whether a channel has a value for me to read?
I don't want to block when reading a channel. I want to see whether it has a value. If it does have one, I'll read it. If it doesn't have one (yet), I'll do something else and check back again later.
The only non-blocking operation I know of to read from a channel is inside a select block having a default case :
select {
case x, ok := <-ch:
if ok {
fmt.Printf("Value %d was read.\n", x)
} else {
fmt.Println("Channel closed!")
}
default:
fmt.Println("No value ready, moving on.")
}
Please try the non-blocking here
Note about previous answers: the receive operator itself is now a blocking operation, as of Go 1.0.3 . The spec has been modified. Please try the blocking here (deadlock)
If you're doing this often then it's probably not a great design and you might be better off spawning another goroutine to do whatever work you're planning to do when there isn't anything to read from the channel. The synchronous/blocking nature of Go's channels make code easier to read and reason about while the scheduler and cheap goroutines means that async calls are unnecessary since waiting goroutines take up very little resources.
Unfortunately, the previous answers are incorrect. The spec clearly says that you CAN use channels this way using len() function, but only if you specified the channel capacity - the buffer length for a channel while making it. If you omitted a channel capacity while making it - the channel operations are always blocking.
You don't, at least not for synchronous (unbuffered) channels. There is no way to tell if a value is waiting without asking to take the value from the channel.
For buffered channels, you technically can use the len function to do what you describe, but you really, really shouldn't. Your technique is invalid.
The reason is that it represents a race condition. Given channel ch, your goroutine might see that len(ch) > 0 and conclude that there is a value waiting. It cannot conclude however, that it can read from the channel without blocking--another goroutine might empty the channel between the time you check len and the time your receive operation runs.
For the purpose you described, use select with a default case as Ripounet showed.
WARNING: This is no longer accurate, see the answer below.
From the docs:
If a receive expression is used in an
assignment or initialization of the
form
x, ok = <-ch
x, ok := <-ch
var x, ok = <-ch
the receive operation becomes
non-blocking. If the operation can
proceed, the boolean variable ok will
be set to true and the value stored in
x; otherwise ok is set to false and x
is set to the zero value for its type
In most cases relying on such information is a really bad design choice. Not even saying about how it's dirty in it's implementation.
So, do not implement the following steps to detect if channel is ready for read at runtime:
define hchan waitq sudog structs as defined here - https://golang.org/src/runtime/chan.go
use "unsafe" package to cast channel to pointer to hchan struct
read sendq field of this struct to get listeners
read first sudog and read msg field from there.
cast msg to the appropriate type for the channels using "reflect" and "unsafe"