-
Notifications
You must be signed in to change notification settings - Fork 25.6k
[Refactoring] Ec2 and GCS plugins build client lazily #31250
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
[Refactoring] Ec2 and GCS plugins build client lazily #31250
Conversation
|
Pinging @elastic/es-core-infra |
jaymode
left a comment
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 like the concept; left some requests for changes. Also, we should have unit tests for the lazy class
| import java.util.Objects; | ||
| import java.util.function.Consumer; | ||
|
|
||
| public class Lazy<T, E extends Exception> { |
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.
Please add javadocs for this class and all methods. Can we make the class final? Also, what about LazyInitializable as the name
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.
Done
| throw new ElasticsearchException("This is unexpected", e); | ||
| } | ||
| // the count will be decreased by {@codee AmazonEc2Reference#close} | ||
| result.incRef(); |
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 increment reference twice on creation?
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.
Yes, this was a mistake, good catch. Ideally this should've been catched by a test. I think there's a TODO (if not for this plugin, for S3) about this test missing. I will address in a follow-up PR.
| try { | ||
| result = super.getOrCompute(); | ||
| } catch (final Exception e) { | ||
| throw new ElasticsearchException("This is unexpected", e); |
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.
use throw ExceptionsHelper.convertToRuntime(e);
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.
good to know, thanks!
| IdleConnectionReaper.shutdown(); | ||
| } | ||
|
|
||
| private static class LazyAmazonEc2Reference extends Lazy<AmazonEc2Reference, Exception> { |
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.
rather than a class for this, can we add a Consumer for the value on get/compute to increment the ref count? Then lazy can be final
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.
done, I think it's cleaner like you proposed since you don't have to study the super implementation when extending.
| return result == null ? maybeCompute(supplier) : result; | ||
| } | ||
|
|
||
| public synchronized void clear() { |
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.
maybe call this reset
|
Thanks for the review @jaymode . I have polished Can you please take another look? |
jaymode
left a comment
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 left a few naming suggestions. Otherwise LGTM
| public final class LazyInitializable<T, E extends Exception> { | ||
|
|
||
| private final CheckedSupplier<T, E> supplier; | ||
| private final Consumer<T> primer; |
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.
how about onGet as a name instead of primer
|
|
||
| private final CheckedSupplier<T, E> supplier; | ||
| private final Consumer<T> primer; | ||
| private final Consumer<T> finalizer; |
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.
how about onReset instead of finalizer? finalizer makes me think of garbage collection
|
Thank you for the swift feedback! You are a rare breed of an engineer and a naming oracle 🎩 |
This PR is the refactoring mentioned here: #29135
TBC the clients (
AmazonEC2andStorage) were already built lazily (and cached and reused) for the afore mentioned plugins. This is the refactoring of that logic. The 'client settings' and the 'client instance' always had to go together which made the code bug prone, i.e. when the settings changed you had to make sure the client was destroyed so that it was lazily rebuilt using the new settings.For the
discovery-ec2andrepository-gcsplugins, it replaces the duality '(map) client settings' - '(map) client instance' with a lazy client supplier. TheSupplierencapsulates the settings required to build the client. The lazy supplier caches the returned value once computed. This factors out the memoize supplier behavior (e.g.elasticsearch/plugins/repository-s3/src/main/java/org/elasticsearch/repositories/s3/InternalAwsS3Service.java
Line 75 in 918827c
Lazyinstance.This change was not required for the
repository-azureplugin as it does not caches client instances (hence only the settings are stored) because client instances are not thread-safe. This change cannot be applied to therepository-s3plugin, until the feature branch reload-secure-store-action is merged, because this plugin explicitly requires the settings to be stored so that they can be overriden from the cluster state (elasticsearch/plugins/repository-s3/src/main/java/org/elasticsearch/repositories/s3/S3Repository.java
Line 223 in 918827c
Originally, the goal for this refactoring was much more ambitious: to have an abstract component that creates and caches clients for all plugins that have clients using secure settings. But this is currently not possible, as the plugin requirements are quite diverse, eg:
discovery-ec2andrepository-s3haveCloseable, thread-safe clients, but therepository-azureclients are not thread-safe.repository-gcsclients are thread-safe but notCloseable.discovery-ec2plugin only uses one client.Relates #29135
CC @elastic/es-security