You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@karaf.apache.org by Steinar Bang <sb...@dod.no> on 2020/08/30 07:15:50 UTC

Are there rules for DS components' constructors and @Activate methods?

Are there rules that should be followed for DS components' constructors
and @Activate methods?

I.e. stuff like
 1. Not run for a too long time (e.g. not block, waiting for an HTTP response)
 2. Not fail (i.e. never throw an exception)
 3. Other?

Thanks!

- Steinar


Re: Are there rules for DS components' constructors and @Activate methods?

Posted by Tim Ward <ti...@paremus.com>.

> On 1 Sep 2020, at 20:09, Steinar Bang <sb...@dod.no> wrote:
> 
>>>>>> Tim Ward <ti...@paremus.com>:
> 
>>> 1. Not run for a too long time (e.g. not block, waiting for an HTTP response)
> 
>> Basic answer:
>> Yes, you should avoid blocking in callbacks generally. The thread is
>> not your own and by blocking you could halt the entire Service
>> Component Runtime, potentially halting (or even deadlocking) the
>> system. If you need to do something long-running then create your own
>> thread to do it.
> 
> Ok.
> 
>> Advanced answer:
>> If you have a long-running asynchronous startup then the default
>> “lazy” behaviour of DS can be problematic. Your component will be
>> registered as a service before it is activated, then activated when it
>> is first retrieved. This activation will complete when your @Activate
>> method exits, even though your asynchronous startup is still
>> running. You will therefore either need to block incoming calls until
>> the asynchronous startup finishes (including dealing with failures),
>> or throw exceptions until you are reay (yuck!).
> 
> I've been bitten by the lazy behaviour earlier so all of my DS
> components are
> @Component(immediate=true)

This isn’t a good idea in general. Lazy start of services allows for better startup and less “bouncing” if/when things rewire. There’s a reason it’s the default behaviour for components that advertise services. Components that don’t advertise services (using SCR) are always immediate because there wouldn’t be any way to trigger lazy activation.

> 
>> A better option in these cases can be to *not* let DS register your
>> component as a service, but instead to programatically register your
>> service object after it has completed activation. In this case writing
>> a DS component that is a lifecycle manager and collector of
>> dependencies, but not the actual service object, can be very helpful.
> 
> Do I need to get hold of the BundleContext and call registerService()
> old style?
> 
> Or is there some new and elegant way of doing this?

BundleContext.registerService() and BundleContext.unregisterService() are your friends here. Be sure that you’re *always* unregistering any service that you’ve registered (as opposed to ones that SCR has registered on your behalf) before your component deactivates. You can have the BundleContext passed to you in activate, or in the latest DS spec versions via field/constructor injection.

> 
>>> 2. Not fail (i.e. never throw an exception)
> 
>> You should definitely fail if the component is broken. Throwing an
>> exception from a constructor or @Activate method will cause the
>> component to be unregistered from the service registry and marked as
>> failed in the service component runtime. You should not “silently
>> fail” and leave a broken service object.
> 
> Ah, OK!  Good to know.  I may have to rewrite some components...:-)
> 
> What happens when an exception is thrown in a separate thread started to
> avoid blocking?
> 
> Will that fail the component?
> 
> Or is it just exceptions thrown from the exception or the @Activate
> method that will fail the component.

The exit status of the activate is what matters. If the activate method returns cleanly (no exception) then the component instance is “ready for use” regardless of what’s happening in other threads. If the activate method throws an exception then the component has failed and is not available for use. This is why asynchronous startup is challenging for components that SCR registers as services - the activate method returns and so the component instance is passed to the person requesting the service, even though the asynchronous work isn’t finished.

In the case where your asynchronous startup might fail then you definitely need to take a look at the “advanced” usage pattern I outlined. A failure in the asynchronous startup should prevent you from registering your object as a service (unless for some unlikely reason it still makes sense as a service after the failure). The general rule of thumb is “only register working services”.

> 
>>> 3. Other?
> 
>> Make sure to correctly define the optionality and cardinality of your
>> dependencies, including dependencies that you have on
>> configuration. Only let the container start your component when it is
>> actually able to do its job.
> 
> Ok.
> 
>> I hope this helps,
> 
> Very helpful, and very clarifying!
> 
> Thanks! :-)
> 


Re: Are there rules for DS components' constructors and @Activate methods?

Posted by Steinar Bang <sb...@dod.no>.
>>>>> Tim Ward <ti...@paremus.com>:

>> 1. Not run for a too long time (e.g. not block, waiting for an HTTP response)

> Basic answer:
> Yes, you should avoid blocking in callbacks generally. The thread is
> not your own and by blocking you could halt the entire Service
> Component Runtime, potentially halting (or even deadlocking) the
> system. If you need to do something long-running then create your own
> thread to do it.

Ok.

> Advanced answer:
> If you have a long-running asynchronous startup then the default
> “lazy” behaviour of DS can be problematic. Your component will be
> registered as a service before it is activated, then activated when it
> is first retrieved. This activation will complete when your @Activate
> method exits, even though your asynchronous startup is still
> running. You will therefore either need to block incoming calls until
> the asynchronous startup finishes (including dealing with failures),
> or throw exceptions until you are ready (yuck!).

I've been bitten by the lazy behaviour earlier so all of my DS
components are
 @Component(immediate=true)

> A better option in these cases can be to *not* let DS register your
> component as a service, but instead to programatically register your
> service object after it has completed activation. In this case writing
> a DS component that is a lifecycle manager and collector of
> dependencies, but not the actual service object, can be very helpful.

Do I need to get hold of the BundleContext and call registerService()
old style?

Or is there some new and elegant way of doing this?

>> 2. Not fail (i.e. never throw an exception)

> You should definitely fail if the component is broken. Throwing an
> exception from a constructor or @Activate method will cause the
> component to be unregistered from the service registry and marked as
> failed in the service component runtime. You should not “silently
> fail” and leave a broken service object.

Ah, OK!  Good to know.  I may have to rewrite some components...:-)

What happens when an exception is thrown in a separate thread started to
avoid blocking?

Will that fail the component?

Or is it just exceptions thrown from the exception or the @Activate
method that will fail the component.

>> 3. Other?

> Make sure to correctly define the optionality and cardinality of your
> dependencies, including dependencies that you have on
> configuration. Only let the container start your component when it is
> actually able to do its job.

Ok.

> I hope this helps,

Very helpful, and very clarifying!

Thanks! :-)


Re: Are there rules for DS components' constructors and @Activate methods?

Posted by Tim Ward <ti...@paremus.com>.
> Are there rules that should be followed for DS components' constructors
> and @Activate methods?
> 
> I.e. stuff like
> 1. Not run for a too long time (e.g. not block, waiting for an HTTP response)

Basic answer:
Yes, you should avoid blocking in callbacks generally. The thread is not your own and by blocking you could halt the entire Service Component Runtime, potentially halting (or even deadlocking) the system. If you need to do something long-running then create your own thread to do it.

Advanced answer:
If you have a long-running asynchronous startup then the default “lazy” behaviour of DS can be problematic. Your component will be registered as a service before it is activated, then activated when it is first retrieved. This activation will complete when your @Activate method exits, even though your asynchronous startup is still running. You will therefore either need to block incoming calls until the asynchronous startup finishes (including dealing with failures), or throw exceptions until you are ready (yuck!). 

A better option in these cases can be to *not* let DS register your component as a service, but instead to programatically register your service object after it has completed activation. In this case writing a DS component that is a lifecycle manager and collector of dependencies, but not the actual service object, can be very helpful.

> 2. Not fail (i.e. never throw an exception)

You should definitely fail if the component is broken. Throwing an exception from a constructor or @Activate method will cause the component to be unregistered from the service registry and marked as failed in the service component runtime. You should not “silently fail” and leave a broken service object.

> 3. Other?

Make sure to correctly define the optionality and cardinality of your dependencies, including dependencies that you have on configuration. Only let the container start your component when it is actually able to do its job.

I hope this helps,

Tim

> On 30 Aug 2020, at 10:50, Steinar Bang <sb...@dod.no> wrote:
> 
>>>>>> Jean-Baptiste Onofre <jb...@nanthrax.net>:
> 
>> Hi,
>> I’m not sure I understand your question.
> 
> I was just asking about general guidelines to follow for DS
> components. I.e. things that should be avoided?
> 
> It's peripherally releated to the other question, but only
> peripherally.  
> 
> The thought struck me while pondering the issue of the other thread, so
> I tried to google for guidelines for DS components.  But didn't find any
> good answers, so I figured I might as well ask.
> 


Re: Are there rules for DS components' constructors and @Activate methods?

Posted by Steinar Bang <sb...@dod.no>.
>>>>> Jean-Baptiste Onofre <jb...@nanthrax.net>:

> Hi,
> I’m not sure I understand your question.

I was just asking about general guidelines to follow for DS
components. I.e. things that should be avoided?

It's peripherally releated to the other question, but only
peripherally.  

The thought struck me while pondering the issue of the other thread, so
I tried to google for guidelines for DS components.  But didn't find any
good answers, so I figured I might as well ask.


Re: Are there rules for DS components' constructors and @Activate methods?

Posted by Jean-Baptiste Onofre <jb...@nanthrax.net>.
Hi,

I’m not sure I understand your question.

In the other threads, my proposal was to:

1. Use scr to run the controller component. This component activate basically starts the HTTP listener.
2. The http listener creates a thread on request doing the logic.

(Maybe I don’t fully understand your use case)

Thoughts ?

Regards
JB

> Le 30 août 2020 à 09:15, Steinar Bang <sb...@dod.no> a écrit :
> 
> Are there rules that should be followed for DS components' constructors
> and @Activate methods?
> 
> I.e. stuff like
> 1. Not run for a too long time (e.g. not block, waiting for an HTTP response)
> 2. Not fail (i.e. never throw an exception)
> 3. Other?
> 
> Thanks!
> 
> - Steinar
>