-
Notifications
You must be signed in to change notification settings - Fork 24.6k
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
Remove SpawnModules #12783
Comments
+1 |
++ |
personally I find having a hierarchy of modules helpful to keep things clean, more modular and more testable:
A should only know about B & E each module knows the minimum it needs to know in order to function. With a flatten model the dependency rules are quite weak:
everyone knows about everyone... no clear dependency rules... everything is allowed. One thing I like about the hierarchy model is that if you follow the rules it forces you to think. That is, if you see that for some reason dependencies leak out of their boundaries - you probably did something wrong. We've had plenty of discussion on this topic already in #12744, so not going to repeat everything again. If most agree to remove this.... it's fine... as long as the end result doesn't turn out to be worse than where we started. |
@uboness I totally understand where you are coming from. The last couple of months elasticsearch has undergone some massive changes since we are basically not able to cope with the amount of classes and abstractions, number of packages etc. It's largely grown over the years and taking several steps back here is a reasonable thing to do. So what does this mean, we mainly folded classes into larger and more general classes, removed packages containing a single class or like a handful, removed wiring services via guice and use good old ctors. We have a class @Override
public Iterable<? extends Module> spawnModules() {
return ImmutableList.of(
new SearchServiceModule(settings),
new TransportSearchModule(),
new HighlightModule(),
new SuggestModule(),
new FunctionScoreModule(),
new AggregationModule(),
new FetchSubPhaseModule());
} almost all of them follow a simple pattern: public class FooModule extends AbstractModule {
public void registerFoo(Foo foo) { ... }
@Override
protected void configure() { ... }
} I think stuff would be way simpler if we would merge them all into public class SearchModule extends AbstractModule {
public void registerHighlighter(Class<? extends Highlighter> clazz) { ... }
public void registerSuggester(Class<? extends Suggester> suggester) { ... }
public void registerFetchSubPhase(Class<? extends FetchSubPhase> subPhase) { ... }
public void registerParser(Class<? extends ScoreFunctionParser> parser) { .. }
public void registerStream(SignificanceHeuristicStreams.Stream stream) { ... }
public void registerStream(MovAvgModelStreams.Stream stream) { ... }
} This is simple to use, clear and reduces bloat. Abstractions are added via the individual classes you can register that is a clear interface. The fact that |
The ClusterModule contained a couple submodules. This moves the functionality from those modules into ClusterModule. Two of those had to do with DynamicSettings. This change also cleans up how DynamicSettings are built, and enforces they are added, with validators, in ClusterModule. See elastic#12783.
The IndicesModule was made up of two submodules, one which handled registering queries, and the other for registering hunspell dictionaries. This change moves those into IndicesModule. It also adds a new extension point type, InstanceMap. This is simply a Map<K,V>, where K and V are actual objects, not classes like most other extension points. I also added a test method to help testing instance map extensions. This was particularly painful because of how guice binds the key and value as separate bindings, and then reconstitutes them into a Map at injection time. In order to gain access to the object which links the key and value, I had to tweak our guice copy to not use an anonymous inner class for the Provider. Note that I also renamed the existing extension point types, since they were very redundant. For example, ExtensionPoint.MapExtensionPoint is now ExtensionPoint.ClassMap. See elastic#12783.
Custom repository types are registered through the RepositoriesModule. Later, when a specific repository type is used, the RespositoryModule is installed, which in turn would spawn the module that was registered for that repository type. However, a module is not needed here. Each repository type has two associated classes, a Repository and an IndexShardRepository. This change makes the registration method for custom repository types take both of these classes, instead of a module. See elastic#12783.
The IndicesModule was made up of two submodules, one which handled registering queries, and the other for registering hunspell dictionaries. This change moves those into IndicesModule. It also adds a new extension point type, InstanceMap. This is simply a Map<K,V>, where K and V are actual objects, not classes like most other extension points. I also added a test method to help testing instance map extensions. This was particularly painful because of how guice binds the key and value as separate bindings, and then reconstitutes them into a Map at injection time. In order to gain access to the object which links the key and value, I had to tweak our guice copy to not use an anonymous inner class for the Provider. Note that I also renamed the existing extension point types, since they were very redundant. For example, ExtensionPoint.MapExtensionPoint is now ExtensionPoint.ClassMap. See #12783. Backport of #12921
Custom repository types are registered through the RepositoriesModule. Later, when a specific repository type is used, the RespositoryModule is installed, which in turn would spawn the module that was registered for that repository type. However, a module is not needed here. Each repository type has two associated classes, a Repository and an IndexShardRepository. This change makes the registration method for custom repository types take both of these classes, instead of a module. See #12783. Backport of #12948.
The last use case of spawn modules was for plugins. This change handles plugin modules directly, and removes SpawnModules. closes elastic#12783
This change makes modules added by plugins come before others, as it was before elastic#12783. The order of configuration, and thereby binding, happens in the order modules are received, and without this change, some plugins can get *insane* guice errors (500mb stack trace).
…t get the compiler to stop complaining) More information and clues here: elastic/elasticsearch#12783
…t get the compiler to stop complaining) More information and clues here: elastic/elasticsearch#12783
This is a spinoff from #12744. SpawnModules is a way to have modules produce sub modules. However, one way they have been used in the past is broken since we now have plugin classloader isolation. Some extension points used to allow plugging in an entire module "implementation". This is far too crazy for us to maintain in ES. It also leads to having lots of tiny modules that bind just a handful of classes.
We should remove this interface, and flatten the modules we have. All extension points should be class implementation based, by registering custom implementations with the module responsible for binding a given class. This has a bunch of benefits, like:
The text was updated successfully, but these errors were encountered: