> On 1 Sep 2020, at 20:09, Steinar Bang <[email protected]> wrote:
> 
>>>>>> Tim Ward <[email protected]>:
> 
>>> 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! :-)
> 

Reply via email to