-
Notifications
You must be signed in to change notification settings - Fork 119
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
fix: only replace refresh result if successful or current result is invalid #561
Conversation
13e943b
to
ca52213
Compare
… result is invalid
ca52213
to
a2464fd
Compare
96c0082
to
34159ac
Compare
nextInstanceData = Futures.immediateFuture(performRefresh()); | ||
} | ||
} else { | ||
forceRefresh(); | ||
} |
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 the logic we want here is:
On error:
if current is invalid:
replace current
next = new new refresh
Since we know this refresh failed, we always want to schedule a new one. We just don't want it to replace "current" if we think "current' might still be good.
public void onFailure(Throwable t) { | ||
logger.log(Level.WARNING, | ||
"An error occurred while performing refresh. Retrying immediately.", t); | ||
if (getInstanceData().getExpiration().toInstant().isBefore(Instant.now())) { |
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.
We need to be careful here. There are at least two problems I see with the current code.
- If "current" is in a bad state (e.i. error) it'll throw an (maybe unrelated) error and nothing past this will happen
- if "current" is this thread (because we've already forced refresh), this will - well I'm not sure. Block forever?
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 don't think we'd ever get into a position where current is still pending, since this callback happens after refreshFuture has completed. The first problem is something to think about though. how can we check the validity of the instance data here, without potentially throwing errors. Would a try/catch work, where we try getInstanceData
and if we get an error, we replace current
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.
Yea, I think I would go with a try/catch around it. Just to clarify - you are sure that the callback will trigger after the future is completed?
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.
One thing to think about - I think we actually want the replace of current
and next
to happen before the future is returned. Otherwise you may introduce a race condition where we return, fail to connect, and force refresh before the callback is executed
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.
Yeah, the callback will definitely trigger after the future is completed. I get what you're saying with the race condition, where a force refresh could be triggered before the callback, but how can we replace current
before we know the future's result if our goal is to avoid replacing a valid InstanceData
with an invalid one?
I think in the case where a force refresh is triggered before the callback, the worst that would happen is that we get an extra refresh attempt a minute later, since the rate limiter will delay the force refresh anyway. If the refresh attempt is successful, then we'd end up replacing a valid result with another (hopefully) valid result, or wait for another refresh attempt to fix it.
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.
To clarify, I think it's preferable if whatever the callback behavior is (replacing current or just rescheduling) before the future counts as "done" .
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.
Can you use [thenApply
](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#thenApply-java.util.function.Function-) for that?
…java Co-authored-by: Kurtis Van Gent <[email protected]>
…/cloud-sql-jdbc-socket-factory into update-refresh-logic
c2a38b6
to
ebe4d3b
Compare
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.
LGTM, minus my one nit. Can we make sure we test it in Cloud Run for an extended period of time (~24hours?) before merging?
core/src/main/java/com/google/cloud/sql/core/CloudSqlInstance.java
Outdated
Show resolved
Hide resolved
…java Co-authored-by: Kurtis Van Gent <[email protected]>
Good to know! I'll merge this then. Thanks! |
Change Description
Checklist
bug/issue
before writing your code! That way we can discuss the change, evaluate
designs, and agree on the general idea.
Relevant issues: