Defer errors until Flush to avoid incomplete batches - #324
nickgarlis wants to merge 1 commit into
Conversation
Any create/update/delete operation that returns a validation or marshalling error can leave the message batch in an incomplete state due to short-circuiting. This can result in either: - Non-atomic transactions if Flush is called (incomplete batch) - Users being unable to clear the incomplete batch (no API exposed) This change ensures that errors are collected and deferred until Flush. Instead of returning immediately, the following methods now append errors to a slice checked at Flush: - AddSet - DelRule - SetAddElements See: google#323
just close connection without flush? |
Yeah that could be an option but IIUC, that's not something we want to do when the connection is lasting. |
|
what is the value of making the connection lifetime as long as possible? If the goal is to save resources, then we are wasting resources by continuing to work with the connection until the next Flush, although we could already know that an error has occurred and we need to stop doing unnecessary work. Also, long live connections may lead to leaks. |
|
Thanks for explaining.
IIUC, your argument is that since memory is already being used while the message accumulates, keeping the connection open doesn’t really save much. That makes sense, but I still think there are cases where you’d want bigger, frequent messages (e.g. a daemon updating geo ipsets). In that situation, why force a connection close on validation failure?
Do you have any examples of such leaks ? Are they caused by bugs in the underlying libraries ?
Would something like this actually make debugging a lot worse? Errors could be made richer and carry identifiers for the failing objects: err := conn.Flush()
if err != nil {
if validationErr, ok := err.(ValidationError); ok {
fmt.Println("ValidationError:", validationErr)
} else if marshallingErr, ok := err.(MarshallingError); ok {
fmt.Println("MarshallingError:", marshallingErr)
} else if errno, ok := err.(syscall.Errno); ok {
fmt.Println("syscall.Errno:", errno)
} else {
fmt.Println("Unknown error:", err)
}
}My argument is that your message is only really complete when you're ready to Flush. For example an anonymous set that is not tied to a rule would result in a kernel This is not an entirely new pattern either. It seems that stateful objects are also implemented in a similar way. See Line 114 in 207a463
AFAIU, there is no way of doing this without adding some kind of validation on Flush() which puts you back in the same spot. Using the anonymous set example again, you’d still end up with a Flush error that references a set somewhere far up in the message. |
Any create/update/delete operation that returns a validation or marshalling error can leave the message batch in an incomplete state due to short-circuiting. This can result in either:
This change ensures that errors are collected and deferred until Flush. Instead of returning immediately, the following methods now append errors to a slice checked at Flush:
See: #323