-
Notifications
You must be signed in to change notification settings - Fork 779
Maintaining ReadyMarkers in a dedicated service #4203
Conversation
@@ -0,0 +1,7 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> |
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.
This file was committed by accident, right? :)
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.
oh yes, thanks!
What is the reason to open the trackers async and create multiple schedulers that only use case is to schedule one Job on activation? Does the open of a tracker block the activation such long? |
private final String type; | ||
|
||
public ReadyMarkerFilter() { | ||
this.type = null; |
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.
this(null, null);
this.identifier = identifier; | ||
} | ||
|
||
public String getType() { |
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.
You could mark that the return type is non null.
return type; | ||
} | ||
|
||
public String getIdentifier() { |
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.
You could mark that the return type is non null.
@Component | ||
public class ReadyServiceImpl implements ReadyService { | ||
|
||
private static final Logger logger = LoggerFactory.getLogger(ReadyServiceImpl.class); |
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 didn't see the need to use a logger in a static context, so could we keep the logger instance non static?
public class ReadyServiceImpl implements ReadyService { | ||
|
||
private static final Logger logger = LoggerFactory.getLogger(ReadyServiceImpl.class); | ||
private static final ReadyMarkerFilter ANY = new ReadyMarkerFilter(); |
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.
Perhaps we could make the ANY constructor (that uses null twice) private to and use a static function that returns an instance (no need for a singleton). Perhaps the meaning of ReadyMarkerFilter.any()
is more intuitive then new ReadyMarkerFilter()
.
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.
If i make that private, there is no public constructor left. My intention was to keep the one with arguments private in order to prevent the constructor-mess we had at other places and rather have the builder-like pattern using with...()
-Methods.
So do I understand you right that using ReadyMarkerFilter.any().withType("...");
is the usage you are suggesting?
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.
No 😉
If I understand the current situation correctly you can create three different type of ready marker filters.
- filter type, created by
ReadyMarkerFilter.withType(String type)
- filter identifier, created by
ReadyMarkerFilter.withIdentifier(String type)
- filter nothing (the any one), created by
new ReadyMarkerFilter()
Correct me if I am wrong.
So, I just think about making all constructors private and use for the last one a factory method, too. All three functions should return immutable objects.
- filter type, created by
ReadyMarkerFilter.withType(String type)
- filter identifier, created by
ReadyMarkerFilter.withIdentifier(String type)
- filter nothing (the any one), created by
ReadyMarkerFilter.any()
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.
Ah, that's the misunderstanding... the with...(...)
-Methods are not static. Therefore you can create:
- filter nothing, created by
new ReadyMarkerFilter()
- filter type, created by
new ReadyMarkerFilter().withType(String type)
- filter identifier, created by
new ReadyMarkerFilter().withIdentifier(String identifier)
- filter for both, created by
new ReadyMarkerFilter().withType(String type).withIdentifier(String identifier)
The reasoning was to have a design is that it can be evolved/extended with further parameters without creating a mess with the string arguments in constructors. I'm really not sure it these two parameters will be the only ones needed in future.
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.
the
with...(...)
-Methods are not static
It seems I have forgotten how to read...
Yes, during tracker-opening, all matching bundles will be "added" to that tracker synchronously by the framework. |
8ea28ba
to
e6233e7
Compare
@@ -41,18 +46,27 @@ | |||
private XmlDocumentBundleTracker<List<ConfigDescription>> configDescriptionTracker; | |||
|
|||
private ConfigI18nLocalizationService configI18nLocalizerService; | |||
private ReadyService readyService; | |||
|
|||
private ScheduledExecutorService scheduler = ThreadPoolManager.getScheduledPool("xml-processing"); |
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.
Could you define "xml-processing" somewhere as a constant and reuse it? Would make it easier to keep track of the created thread pools.
} | ||
ScheduledFuture<?> future = scheduler.schedule(() -> { | ||
processBundle(bundle); | ||
ScheduledFuture<?> future = scheduler.schedule(new Runnable() { |
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.
Could you use "submit"?
bindingInfoReader, this, READY_MARKER); | ||
bindingInfoTracker.open(); | ||
bindingInfoReader, this, READY_MARKER, readyService); | ||
trackerJob = scheduler.schedule(() -> { |
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.
submit?
thingTypeTracker.open(); | ||
READY_MARKER, readyService); | ||
|
||
trackerJob = scheduler.schedule(() -> { |
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.
submit?
* @author Simon Kaufmann - initial contribution and API. | ||
* | ||
*/ | ||
@NonNullByDefault |
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.
Did we already agree on using that annotation?
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.
No idea, I lost the overview...
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.
Check this to get an overview again :-)
} | ||
|
||
private void notifyTrackers(ReadyMarker readyMarker, Consumer<ReadyTracker> action) { | ||
trackers.entrySet().stream().filter(entry -> { |
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.
Not a change request but a suggestion:
trackers.entrySet().stream().filter(entry -> entry.getValue().apply(readyMarker)).map(entry -> entry.getKey())
.forEach(action);
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.
or
trackers.entrySet().stream().filter(entry -> entry.getValue().apply(readyMarker)).map(Entry::getKey)
.forEach(action);
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've been using the block-notation on purpose, to force the auto-formatter to insert line-breaks in places where the human brain can follow. I couldn't figure out how to make JDT do do something similar automatically. Do you by any chance have an idea?
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.
Ah now I understand. What I usually do to achieve this is that I manually make changes to the stream notations and turn off autoformatter for certain section.
// @formatter:off
trackers.entrySet().stream()
.filter(entry -> entry.getValue().apply(readyMarker))
.map(Entry::getKey)
.forEach(action);
// @formatter:on
...instead of using the SCR for it. Signed-off-by: Simon Kaufmann <[email protected]>
...instead of using the SCR for it.
The reason behind this is that on at least one commercial OSGi server when running with activated security manager, registering services takes quite long (up to several hundreds of milliseconds per service). When running on limited hardware resources, this significantly impacts the startup times. Therefore it does not look like such a nice idea to register hundreds of services just as "Ready Markers".
As an improvement to this, I suggest to have a single service which holds these ready markers and other components can register as listeners.
This does not mean we shouldn't use services for the "startup level"solution (see #1896). However, it simply turned out that it is not necessarily a good idea to flood the SCR with "marker" services.
Signed-off-by: Simon Kaufmann [email protected]