Yup, it got a bit windy ;-) I put it on my website as a blog since I've no good
other place at the moment.
http://aqute.biz/2018/08/02/the-service-window.html
<http://aqute.biz/2018/08/02/the-service-window.html>
Let me know if things are unclear. Kind regards,
Peter Kriens
> On 2 Aug 2018, at 11:58, David Leangen via osgi-dev <[email protected]>
> wrote:
>
>
> Wow! That is a lot to digest.
>
> I’ll need to get back to you in a few days/weeks/months/years. :-D
>
> Thanks so much!!
>
>
> Cheers,
> =David
>
>
>
>
>> On Aug 2, 2018, at 18:38, Peter Kriens <[email protected]
>> <mailto:[email protected]>> wrote:
>>
>>
>> ## Keep Passing the Open Windows
>>
>> You did read the classic [v2Archive OSGi enRoute App note][5] about this
>> topic? It has been archived by the OSGi to [v2Archive OSGi enRoute web
>> site][3]. It handles a lot of similar cases. There is an accompanying
>> workspace [v2Archive OSGi enRoute osgi.enroute.examples.concurrency
>> <https://github.com/osgi/osgi.enroute.examples.concurrency>][7]
>>
>> Anyway, I am not sure if you want to solve this pragmatic or pure?
>>
>> ## Pragmatic
>>
>> Pragmatic means there is a tiny chance you hit the window where you check if
>> the MyService is unregistered and then use it. If you're really unlucky you
>> just hit the unregistration after you checked it but before you can use it.
>> It works when the unregistration of MyService is rare and the work is long.
>> Yes, it can fail but so can anything so you should be prepared for it.
>>
>> Pragmatic works best as follows:
>>
>> @Component
>> public class MyClass extends Thread {
>> @Reference MyService myService;
>>
>> @Activate void activate() { start(); }
>> @Deactivate void deactivate() { interrupt(); }
>>
>> public void run() {
>> while (!isInterrupted()) {
>> try {
>> MyResult result = doHardWork();
>> if (!isInterrupted())
>> myService.setResult(result);
>> } catch (Exception e) { /* TODO */ }
>> }
>> }
>> }
>>
>> Clearly there is a race condition.
>>
>>
>>
>>
>> ## Pure
>>
>> I once had a use case where we had whiteboard listeners that received
>> events. The frequency and some not so good event listeners that took too
>> much time in their callback. This created a quite long window where it could
>> fail so it often did. For that use case I created a special highly optimized
>> class that could delay the removal of the listener while it was being
>> dispatched. To make it have absolutely minimal overhead was tricky, I even
>> made an Alloy model of it that found some design errors. Anyway, sometimes
>> you have pick one of the bad sides, this was one where delaying the
>> deactivate was worth it.
>>
>> So how would you make this 'purer' by delaying the deactivation until you
>> stopped using it? Since the service is still supposed to be valid during
>> deactivate we could make the setResult() and the deactivate() methods
>> exclude each other. That is, we need to make sure that no interrupt can
>> happen when we check for the isInterrupted() and call myService.setResult().
>> We could use heavy locks but synchronized works fine for me when you realize
>> some of its caveats:
>>
>> * Short blocks
>> * Ensure you cannot create deadlocks
>>
>> So there must be an explicit contract that the MyService is not going to
>> stay away for a long time nor call lots of other unknown code that could
>> cause deadlocks. After all, we're blocking the deactivate() method which is
>> very bad practice in general. So you will trade off one purity for another.
>>
>> @Component
>> public class MyClass extends Thread {
>> @Reference MyService myService;
>>
>> @Activate void activate() { start(); }
>> @Deactivate synchronized void deactivate() { interrupt(); }
>>
>> public void run() {
>> while (!isInterrupted()) {
>> try {
>> MyResult result = doHardWork();
>> synchronized(this) {
>> if (!isInterrupted()) {
>> myService.setResult(result);
>> }
>> }
>> } catch (Exception e) { /* TODO */ }
>> }
>> }
>> }
>>
>> This guarantees what you want … However (you knew this was coming!) there is
>> a reason the service gets deactivated. Even though the _service_ is still
>> valid at that point, there is a reason the _service object_ indicated its
>> unwillingness to play. For example, if MyService was remoted then the
>> connection might have been lost. In general, when you call a service you
>> should be prepared that it fails. (That is why you should always take
>> exceptions into account even if they're not checked.)
>>
>> ## Better API
>>
>> The best solution is usually to turn the problem around. This clearly can
>> only happen when you can influence the API so that is often not a choice. If
>> you can, you can pass a Promise to the myService and calculate in the
>> background. Clearly that means you keep churning doing the hard work. Unless
>> the calculation is very expensive and the unregistration happens often,
>> doing the calculation unnecessary should normally have no practical
>> concerns. If it is, you might want to consider CompletableFuture instead of
>> Promise since it has a cancel() method. (We rejected a cancel since it makes
>> the Promise mutable, but admittedly it is useful. However, it has the same
>> race issues as we discuss here.)
>>
>> @Component
>> public class MyClass {
>>
>> @Reference MyService myService;
>> @Reference PromiseFactory promiseFactory;
>>
>> @Activate void activate() {
>> Promise<MyResult> result = promiseFactory.submit( this::doHardWork );
>> myService.setResult( result );
>> }
>> }
>>
>> This is an example where you see a very weird effect that I first noticed in
>> the eighties during my first big OO design. At first you think the problem
>> is now moved from MyClass to MyService? I think when you try to implement
>> this that you find that the problem mostly _disappeared_. During one of the
>> first large systems I designed I kept feeling we were kicking the hard
>> problems down the road and we still run into a brick wall. However, one day
>> we realized we were done. For some reason the hard problems were solved in
>> the structure of the application and not in specific code. Weird. However,
>> realizing this I often have to cry a bit when I realize how some designs are
>> doing the opposite and make simple things complex :-(
>>
>> ## Multiple Results
>>
>> If you have multiple results to deliver you might want to take a look at the
>> [OSGi PushStream][1]. When I made the initial design for ASyncStreams (feels
>> eons ago :-( ) that inspired the OSGi Push Stream specification this was
>> one of the use cases I had in mind. The Push Stream are intended to handle
>> all the nasty cases and shield you from them. As a bonus, it actually works
>> for multiple receivers as well. Push Streams provide a simple low cost
>> backlink to handle the case where the MyService gets closed. Haven't looked
>> at where Push Stream's ended up but as far as I know they should still be
>> useful when your hard work delivers multiple results. Ah well, I wanted to
>> take a look at it anyway since it has been released now. Let's see how that
>> would look like:
>>
>> @Component
>> public class ProviderImpl extends Thread {
>>
>> @Reference PushStreamProvider psp;
>> @Reference MyService myService;
>>
>> volatile SimplePushEventSource<MyResult> dispatcher;
>>
>> @Activate void activate() throws Exception {
>> dispatcher =
>> psp.createSimpleEventSource(MyResult.class);
>> myService.setResult(dispatcher);
>> start();
>> }
>>
>> @Deactivate void deactivate() {
>> interrupt();
>> }
>>
>> @Override
>> public void run() {
>> try {
>> MyResult r = doHardWork();
>> while (!isInterrupted()) {
>> dispatcher.publish(r);
>> r = doHardWork();
>> }
>> } finally {
>> dispatcher.close();
>> }
>> }
>> }
>>
>> ## Use of Executors
>>
>> As a side note. I've been in systems where everybody was mucking around with
>> ExecutorServices and it became a mess. In [v2Archive OSGi enRoute][3] I
>> always provided an [Executor service][4] that is shared and does proper
>> cleanup when the service getter goes away. (The [v2Archive OSGi enRoute
>> Scheduler][6] was also very nice for this since it provides Cancelable
>> Promises.) Executor Services created statically are horror in OSGi since
>> they are completely oblivious of the OSGi dynamics. And in your case they
>> are totally unnecessary. The only utility they provide to you is that they
>> interrupt the threads. This is trivial to do when you create your own
>> thread. (And messages about the expensiveness of threads are highly
>> exaggerated.) Even if you use an Executor you can pass the thread.
>>
>> Deferred<Thread> deferred = new Deferred<>();
>> Promise<MyResult> promiseFactory.submit( () -> {
>> deferred.resolve( Thread.currentThread() );
>>
>> while ( result == null && !Thread
>> <http://thread.is/>.currentThread().isInterrupted() {
>> … do some hard work
>> }
>> return result;
>> });
>>
>> // deactivate
>> deferred.getPromise().getValue().interrupt();
>>
>> In general, if you go this route, suggest you clearly separate the
>> strategies from the code. I.e. make a separate class to capture the strategy
>> of handling these things. Worst designs are where these are mixed.
>>
>> ## Disclaimer
>>
>> I guess this became a tad long, I guess I will turn it into a blog.
>>
>> Anyway, usually disclaimer: none of the code has been tested so use it at
>> your own peril!
>>
>> Good luck, kind regards,
>>
>> Peter Kriens
>>
>> [1]: https://osgi.org/specification/osgi.cmpn/7.0.0/util.pushstream.html
>> <https://osgi.org/specification/osgi.cmpn/7.0.0/util.pushstream.html>
>> [2]:
>> http://www.plantuml.com/plantuml/png/RP2n2i8m48RtF4NST6WVe4Cj24M7Ka71EII71jjKxYwLlhsXMXghO-w3Z-zFGQoGVTk8QZW1zbQ3J79PNcGc4QwM6524LxXLmwvHH07epX6Zr_mcCo1WsKwU9LIQRQyOn7GAplCDGPa0nmoHfgdud69ekhr2y-pm_ezQEZW6HFzWCDlHyRl5ksXDN6LWsPNaiteIhpUBjk_D2EGRZeVD1PayrdMv4WKu4_xv1G00
>>
>> <http://www.plantuml.com/plantuml/png/RP2n2i8m48RtF4NST6WVe4Cj24M7Ka71EII71jjKxYwLlhsXMXghO-w3Z-zFGQoGVTk8QZW1zbQ3J79PNcGc4QwM6524LxXLmwvHH07epX6Zr_mcCo1WsKwU9LIQRQyOn7GAplCDGPa0nmoHfgdud69ekhr2y-pm_ezQEZW6HFzWCDlHyRl5ksXDN6LWsPNaiteIhpUBjk_D2EGRZeVD1PayrdMv4WKu4_xv1G00>
>> [3]: https://v2archive.enroute.osgi.org/
>> <https://v2archive.enroute.osgi.org/>
>> [4]:
>> https://github.com/osgi/v2archive.osgi.enroute/tree/master/osgi.enroute.executor.simple.provider
>>
>> <https://github.com/osgi/v2archive.osgi.enroute/tree/master/osgi.enroute.executor.simple.provider>
>> [5]: https://v2archive.enroute.osgi.org/appnotes/concurrency.html
>> <https://v2archive.enroute.osgi.org/appnotes/concurrency.html>
>> [6]:
>> https://github.com/osgi/v2archive.osgi.enroute/tree/master/osgi.enroute.scheduler.simple.provider
>>
>> <https://github.com/osgi/v2archive.osgi.enroute/tree/master/osgi.enroute.scheduler.simple.provider>
>> [7]: https://github.com/osgi/osgi.enroute.examples.concurrency
>> <https://github.com/osgi/osgi.enroute.examples.concurrency>
>>
>>>
>>> On 2 Aug 2018, at 02:01, David Leangen via osgi-dev <[email protected]
>>> <mailto:[email protected]>> wrote:
>>>
>>>
>>> Hi Tim,
>>>
>>> Thanks, and this is good advice. The example you give is when the thread is
>>> in the same component that is being deactivated. In this case, as you show,
>>> it is quite trivial to track the activation state of the component in order
>>> to shut down the thread.
>>>
>>> In my case, the trouble I am having is that the long-running thread is in a
>>> component that is different from the component that is getting deactivated.
>>> For instance, building on your example:
>>>
>>> @Component
>>> public class MyClass {
>>>
>>> // Note that I am using a STATIC service
>>> @Reference private MyService myService;
>>>
>>> private final AtomicBoolean closed = new AtomicBoolean();
>>>
>>> @Activate
>>> void start() {
>>> new Thread(this::longStart).run()
>>> }
>>>
>>>
>>> @Deactivate
>>> void stop() {
>>> closed.set(true);
>>> }
>>>
>>> void longStart() {
>>> for(int i = 0; i < 1000000; i++) {
>>>
>>> // This only works if the service object is not stateful,
>>> otherwise we need
>>> // to do a check and throw away an intermediate invalidated
>>> result
>>>
>>> // Understood, but unfortunately the service object is stateful.
>>>
>>> // The problem is that the dependency can be deactivated at any
>>> time, and this
>>> // is happening before “closed" in this component get set to
>>> “true". I do not know how
>>> // to detect the deactivation of the dependency. I need to
>>> determine this pre-emptively,
>>> // not after-the-fact. Otherwise the result will be destructive.
>>>
>>> doSomethingWithMyService(myService);
>>>
>>> // Ideally I would like to do something like this:
>>> if (myServiceIsStillActive())
>>> doSomethingWithMyService(myService);
>>> }
>>> }
>>> }
>>>
>>> In the second example, there is a dynamic @Reference, so I see the point of
>>> using an AtomicReference. However, I am using a static @Reference, so I
>>> doubt that just putting in an AtomicReference will change the timing
>>> problem.
>>>
>>> Any thoughts?
>>>
>>>
>>>
>>> By the way, instead of using a “closed” variable, I am doing something like
>>> this:
>>>
>>> @Activate
>>> void activate()
>>> {
>>> executor = Executors.newSingleThreadExecutor();
>>> }
>>>
>>> void deactivate()
>>> {
>>> executor.shutdownNow();
>>> }
>>>
>>> Then I only need to test for Thread.interrupted(). I assume this has the
>>> same effect as having the check for “closed".
>>>
>>> Cheers,
>>> =David
>>>
>>>
>>>
>>>> On Aug 1, 2018, at 16:59, Tim Ward <[email protected]
>>>> <mailto:[email protected]>> wrote:
>>>>
>>>> Hi David,
>>>>
>>>> In addition to interrupting the worker thread (which is a good idea).
>>>> There are a couple of useful things that you can do using the support from
>>>> java.util.concurrent. For example, setting a closed state:
>>>>
>>>>
>>>> @Component
>>>> public class MyClass {
>>>>
>>>> private final AtomicBoolean closed = new AtomicBoolean();
>>>>
>>>> @Activate
>>>> void start() {
>>>> new Thread(this::longStart).run()
>>>> }
>>>>
>>>>
>>>> @Deactivate
>>>> void stop() {
>>>> closed.set(true);
>>>> }
>>>>
>>>> void longStart() {
>>>> for(int i = 0; i < 1000000; i++) {
>>>> if(closed.get()) {
>>>> break;
>>>> }
>>>> doSomething();
>>>> }
>>>> }
>>>> }
>>>>
>>>> Also if your references are dynamic then you should treat them carefully
>>>>
>>>> @Component
>>>> public class MyClass implements MySlowService {
>>>>
>>>> private final AtomicReference<MyService> myRef = new
>>>> AtomicReference<>();
>>>>
>>>> @Reference(policy=DYNAMIC)
>>>> void setReference(MyService service) {
>>>> myRef.set(service)
>>>> }
>>>>
>>>> void unsetReference(MyService service) {
>>>> // Note that it is *not* safe to just do a set null, see Compendium
>>>> 112.5.12
>>>> myRef.compareAndSet(service, null);
>>>> }
>>>>
>>>> public void longRunningTask() {
>>>> for(int i = 0; i < 1000000; i++) {
>>>> // This only works if the service object is not stateful,
>>>> otherwise we need
>>>> // to do a check and throw away an intermediate invalidated
>>>> result
>>>>
>>>> MyService myService = myRef.get();
>>>> doSomethingWithMyService(myService);
>>>> }
>>>> }
>>>> }
>>>>
>>>> I hope you find these helpful.
>>>>
>>>> Tim
>>>>
>>>>> On 1 Aug 2018, at 05:44, David Leangen via osgi-dev
>>>>> <[email protected] <mailto:[email protected]>> wrote:
>>>>>
>>>>>
>>>>> Hi!
>>>>>
>>>>> I am running into a situation where, what I think is happening is:
>>>>>
>>>>> Component A gets instantiated
>>>>> Component B
>>>>> - references A
>>>>> - gets satisfied once A is satisfied
>>>>> - kicks off a long-running process when one of its methods are called
>>>>> - the long-running process is run in a different thread, with a Promise
>>>>> Component A is no longer satisfied
>>>>> But
>>>>> - the long-running process is still running
>>>>> - the long-running process now references an invalid Component A
>>>>> - the long-running thread fails because of the invalid state of Component
>>>>> A
>>>>> Component B is no longer satisfied
>>>>>
>>>>>
>>>>> So, the long-running component messes things up, but its component has
>>>>> not yet shut down even though its process is still happily running in
>>>>> another thread.
>>>>>
>>>>> I can think of two possible solutions, but not sure which is best and not
>>>>> sure how to implement:
>>>>>
>>>>> 1) Figure out a way to share an ExecutorService between “related”
>>>>> components so that when one component
>>>>> shuts down it will signal to the other related components that their
>>>>> threads are now interrupted
>>>>>
>>>>> 2) In the long-running process, determine if the component that provides
>>>>> the required service
>>>>> is still active before continuing with the havoc-wreaking process
>>>>>
>>>>>
>>>>> Does this sound about right?
>>>>>
>>>>> How would I actually accomplish either of these?
>>>>>
>>>>>
>>>>> Thanks!
>>>>> =David
>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> OSGi Developer Mail List
>>>>> [email protected] <mailto:[email protected]>
>>>>> https://mail.osgi.org/mailman/listinfo/osgi-dev
>>>>> <https://mail.osgi.org/mailman/listinfo/osgi-dev>
>>>>
>>>
>>> _______________________________________________
>>> OSGi Developer Mail List
>>> [email protected] <mailto:[email protected]>
>>> https://mail.osgi.org/mailman/listinfo/osgi-dev
>>> <https://mail.osgi.org/mailman/listinfo/osgi-dev>
>
> _______________________________________________
> OSGi Developer Mail List
> [email protected]
> https://mail.osgi.org/mailman/listinfo/osgi-dev
_______________________________________________
OSGi Developer Mail List
[email protected]
https://mail.osgi.org/mailman/listinfo/osgi-dev