-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Retry refactor to allow for batching to retry. #617
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package syslog | ||
|
||
import ( | ||
"log" | ||
"time" | ||
|
||
"code.cloudfoundry.org/loggregator-agent-release/src/pkg/egress" | ||
) | ||
|
||
// RetryWriter wraps a WriteCloser and will retry writes if the first fails. | ||
type Retryer struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not just represent There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't have a strong opinion on this, but I think I lean toward just putting all this code into There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was thinking about that as well, but when one would introduce the retryer in the way I built it here, it would have more than one benefit:
|
||
retryDuration RetryDuration | ||
maxRetries int | ||
binding *URLBinding | ||
} | ||
|
||
func NewBackoffRetryer( | ||
urlBinding *URLBinding, | ||
retryDuration RetryDuration, | ||
maxRetries int, | ||
) *Retryer { | ||
nicklas-dohrn marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return &Retryer{ | ||
retryDuration: retryDuration, | ||
maxRetries: maxRetries, | ||
binding: urlBinding, | ||
} | ||
} | ||
|
||
// Write will retry writes unitl maxRetries has been reached. | ||
func (r *Retryer) Retry(message []byte, fn func(msg []byte) error) error { | ||
logTemplate := "failed to write to %s, retrying in %s, err: %s" | ||
|
||
var err error | ||
|
||
for i := 0; i < r.maxRetries; i++ { | ||
err = fn(message) | ||
if err == nil { | ||
return nil | ||
} | ||
|
||
if egress.ContextDone(r.binding.Context) { | ||
return err | ||
} | ||
|
||
sleepDuration := r.retryDuration(i) | ||
log.Printf(logTemplate, r.binding.URL.Host, sleepDuration, err) | ||
|
||
time.Sleep(sleepDuration) | ||
} | ||
|
||
return err | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why embed
*Retryer
rather than using a named field to encapsulate the new struct via composition?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that I would prefer composition in this case because I don't see a good reason to exposes the fields and methods of
*Retryer
directly.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was using a Pointer here, so that I could insert the retryer by creating it in the writer factory layer, so that the implementation and logic does not rely on the writers itself to propagate the settings through to the retryer.
Might be a shortcoming due to my limited understanding of Go idiomatic concepts.