You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@sling.apache.org by Bertrand Delacretaz <bd...@apache.org> on 2010/02/15 17:01:43 UTC

New proposal for SLING-490: ServiceWatchdog service in the sling engine bundle

Hi,

Here's a new proposal for SLING-490, for a service that helps find out
when a Sling system is ready to accept requests after startup.

Last discussion (http://markmail.org/thread/4bwmuwj6qnytmrfw) provided
some good ideas, but I think this is much better, with low coupling
and a possibility for bundles to declare additional required services
before they become active, making it easier to have a well defined
startup behavior.

The idea is to add an implementation of the ServiceWatchdog interface
shown below, to the sling engine bundle.
See details of the ServiceWatchdog interface below.

The sling engine bundle activator calls
ServiceWatchdog.addRequiredServices based on configuration values read
from BundleContext.getProperty, useful for repository-less setups.

The SlingMainServlet calls ServiceWatchdog.getMissingServices(), and
returns HTTP status 503 if that's not null. That's the only place
where this info is used by Sling itself.

As soon as the repository becomes available, before making it
available as a SlingRepository service, the AbstractSlingRepository
reads an optional list of additional required services from a
well-known location in the repository, under /system/required-services
for example,

I think this solves our previous concerns w.r.t possible race
conditions at startup depending on which configuration mechanisms are
used: client bundles are free to get the "required services" info from
wherever makes sense for them, and the ServiceWatchdog reacts
immediately to addRequiredServices calls, by clearing its internal
state to force it to be recomputed on the next getMissingServices
call.

The ServiceWatchdog implementation listens to service events and
bundle events, to recompute the list of missing services when needed,
and caches that info as long as no such events are received.

WDYT?

-Bertrand



/** Service that watches a specified set of services,
 *  to check that they are all present.
 */
public interface ServiceWatchdog {
	/**	True if all specified services are present.
	 * 	That info is cached, so calling this is cheap
	 * 	unless relevant services and/or bundles events
	 * 	have been received, causing this to be recomputed.
	 *
	 *	@return null if all required services are present.
	 *		If services are missing, returns a formatted
	 *		string like
	 *		<pre>
	 *		ID:COUNT:CLAZZ:FILTER
	 *		ID:COUNT:CLAZZ:FILTER
	 *		...
	 *		</pre>
	 *		Where each ID:CLAZZ:FILTER line indicates a set of
	 *		services registered with {@link addRequiredServices)
	 *		for which BundleContext.getServiceReferences does not
	 *		return the expected number of services.
	 *	    	
	 */
	String getMissingServices();
	
	/**	Add one or several services to the list of services to watch.
	 * 	The watchdog calls BundleContext.getServiceReferences with
	 * 	the specified parameters to find out if the corresponding
	 * 	services are present.
	 *
	 * 	@param bundleId clazz and filter are tied to this bundle,
	 * 		if it is stopped or uninstalled, the corresponding
	 * 		clazz/filter values are removed from our list.
	 * 	@param count expected size of the array returned by
	 * 		BundleContext.getServiceReferences
	 * 	@param clazz used to call BundleContext.getServiceReferences
	 * 	@param filter used to call BundleContext.getServiceReferences
	 */
	void addRequiredServices(long bundleId, int count, String clazz,
String filter);
}

Re: New proposal for SLING-490: ServiceWatchdog service in the sling engine bundle

Posted by Carsten Ziegeler <cz...@apache.org>.
Hi,

the first question I have is what should happen with the current
SystemStatus service? Should we just drop it? (Which is an incompatible
change, but having two similar services doesn't look appealing either).

More comments inline

Bertrand Delacretaz wrote:
> Hi,
> 
> Here's a new proposal for SLING-490, for a service that helps find out
> when a Sling system is ready to accept requests after startup.
> 
> Last discussion (http://markmail.org/thread/4bwmuwj6qnytmrfw) provided
> some good ideas, but I think this is much better, with low coupling
> and a possibility for bundles to declare additional required services
> before they become active, making it easier to have a well defined
> startup behavior.
> 
> The idea is to add an implementation of the ServiceWatchdog interface
> shown below, to the sling engine bundle.
> See details of the ServiceWatchdog interface below.
While the interface might go into the engine bundle I think the
implementation should not; like we tried with the SystemStatus service,
I think this service should be optional.

> The sling engine bundle activator calls
> ServiceWatchdog.addRequiredServices based on configuration values read
> from BundleContext.getProperty, useful for repository-less setups.
This is implementation specific and should go into a separate bundle.

> The SlingMainServlet calls ServiceWatchdog.getMissingServices(), and
> returns HTTP status 503 if that's not null. That's the only place
> where this info is used by Sling itself.
> 
> As soon as the repository becomes available, before making it
> available as a SlingRepository service, the AbstractSlingRepository
> reads an optional list of additional required services from a
> well-known location in the repository, under /system/required-services
> for example,
I think we shouldn't add this logic to the sling repository (or the
bundle where the sling repository implementation is in). This is
separate or optional stuff which should go into a separate bundle.
Now, the whole watchdog stuff - except the interface - can go in a
single bundle; it can act on events like when the sling repository
service is registered etc.

> 	 *	@return null if all required services are present.
> 	 *		If services are missing, returns a formatted
> 	 *		string like
> 	 *		<pre>
> 	 *		ID:COUNT:CLAZZ:FILTER
> 	 *		ID:COUNT:CLAZZ:FILTER
> 	 *		...
> 	 *		</pre>
> 	 */
> 	String getMissingServices();
If this method should return a list of status information then we should
model it that way and not do clever string concatenation. So something like
List<ServiceStatus> getMissingServices();
or
Iterator<ServiceStatus> getMissingServices()

where ServiceStatus has a getId, getCount etc.

As we already tried to solve this problem with the SystemStatus service
- which seem to fail, I think we should first do an implementation in
the whiteboard and when we're comfortable with it, move this to trunk.

Carsten
-- 
Carsten Ziegeler
cziegeler@apache.org

Re: New proposal for SLING-490: ServiceWatchdog service in the sling engine bundle

Posted by Carsten Ziegeler <cz...@apache.org>.
Felix Meschberger wrote:
> 
> So, here is my proposal:
> 
>  * The configuration is provided by the Configuration Admin
>    service as a factory configuration with the following
>    properties:
> 
>          bundle.symbolic.name
>          bundle.version (optional, defaults to any version)
>          count (optional, defaults to 1)
>          clazz (required)
>          filter (optional, defaults to "no filter")
> 
>  * The SlingMainServlet registers a ManagedServiceFactory
>    listening for these configurations and maintains an
>    internal "state machine". This registration can be done
>    in the SlingMainServlet.activate method (and deregistration
>    in the SlingMainServlet.deactivate method).
> 
>  * The implementation is part of the Sling Engine bundle
>    and is private to the Engine bundle.
> 
>  * The SlingMainServlet uses a simple method:
>        boolean isSystemReady()
>    conveying the state. The method should a non-readyness
>    reason. The SlingMainServlet will just send back 503
>    (or 404 ?) if not ready.
> 
>  * The internal implementation may be registered as a
>    Web Console plugin (or Configuration Printer) to provide
>    administrators with:
> 
>       * details about the system status
>       * configuration form to easily manage the
>         configuration (maybe leveraging the Configuration
>         Admin support of the Web Console similar to how
>         the Commons Log bundle does it on the "Sling Log
>         Support" page.
> 
>  * Using JCR Install, FileInstall, the Web Console, or other
>    means of providing configuraiton, administrators may "fill"
>    the requirements list
> 
> Finally the SystemStatus interface is deprecated and the systemstatus
> bundle is removed (or moved to some attic location).

Sounds good to me, with one additional comment :)
I think we don't need the bundle.symbolic.name/version combo in the
suggested configuration. As this is already maintained through some
external system like jcr install or file install, this can be handled
completly by the admin.
At least both should be optional, but I think we should rather drop it
for now and maybe add it if we really really need it.

Carsten
-- 
Carsten Ziegeler
cziegeler@apache.org

Re: New proposal for SLING-490: ServiceWatchdog service in the sling engine bundle

Posted by Bertrand Delacretaz <bd...@apache.org>.
Hi,

On Tue, Feb 16, 2010 at 9:27 AM, Felix Meschberger <fm...@gmail.com> wrote:
> ...So, here is my proposal:
>
>  * The configuration is provided by the Configuration Admin
>   service as a factory configuration with the following
>   properties:
>
>         bundle.symbolic.name
>         bundle.version (optional, defaults to any version)
>         count (optional, defaults to 1)
>         clazz (required)
>         filter (optional, defaults to "no filter")
>
>  * The SlingMainServlet registers a ManagedServiceFactory
>   listening for these configurations and maintains an
>   internal "state machine". This registration can be done
>   in the SlingMainServlet.activate method (and deregistration
>   in the SlingMainServlet.deactivate method)....

I don't think this allows for my "synchronous configuration" scenario
without special precautions.

Taking the SlingRepository service as an example, the scenario is:

0. SlingMainServlet started, SlingRepository service not present ->
system not ready, servlet returns 503.

1. SlingRepository service starting, activate() called

2. SlingRepository provides additional readyness configurations C,
using Configuration.update(...) in its activate() method.

3. SlingRepository.activate() is done, SlingMainServlet sees
SlingRepository service, declares system ready.

4. SlingMainServlet is notified of configurations C, might happen
later than 3. as Configuration.update() is processed asynchronously by
ConfigurationAdmin.

So between 3. and 4. we have an unwanted switch to system ready and
back, which I want to avoid.

One possible workaround is to register the SlingMainServlet as a
ConfigurationPlugin, so that it is informed of Configuration.update()
calls synchronously. Feels a bit hacky?

Or we go back to my ServiceWatchdog interface. I agree that that
introduces more coupling than what you suggest, but it's simple and
guaranteed to work synchronously.

Thoughts? Other suggestions?

-Bertrand

Re: New proposal for SLING-490: ServiceWatchdog service in the sling engine bundle

Posted by Bertrand Delacretaz <bd...@apache.org>.
Hi,

On Tue, Feb 16, 2010 at 9:27 AM, Felix Meschberger <fm...@gmail.com> wrote:
> ...I have some concerns about the proposed implementation:
>
>  * Returning a formatted string sounds wrong
>  * We have to define public API, which is not used all
>   outside of Engine, except for registering something
>  * We have an issue of where to implement this thing....

Ok, agree with those.

>
> I am considering the following issues:
>
>  ...* The decision of whether a system is to be considered
>   ready or not is mainly an administrative task
>   (rather than a development time decision), we should place
>   the administrator into a position to be able to configure
>   this thing....

Ok, but there's one use case where administration cannot happen, it's
the first Sling startup, from scratch:

1. OSGi state folder is created, launchpad bundles installed and started
2. JCR repository is created by bundle that provides it, optionally
populated by initial content in bundles
3. jcrinstall, if used, installs and starts a number of bundles asynchronously
4. Various services start
5. System is considered ready once all required services are present

I'd like this case to be clean from the http point of view, that is
Sling should return a 503 for *all* http requests (or a holding page,
would be nice) until 5. That's "only" useful in demo/first startup
scenarios, but you don't get a second chance to make a first
impression...

Various schemes involving OSGi configurations might leave room for
"uncertainty windows" where the SlingMainServlet might consider the
system ready because it hasn't received all the configurations yet.

My proposal in the original post prevents this (I think) by having the
JCR repository bundle augment the "system ready" configuration
*synchronously* in the bundle activator.

The SlingMainServlet requires a repository to work, so if the
readyness config is modified synchronously in the repository bundle
activator, we should get a consistent 503 until step 5.

Let's see if that works with your proposal.

>  * The SlingMainServlet is -- inside of Sling -- the only
>   party really intereted in some state. Thus introduction of
>   an externally visible API should probably be prevented

> ... * The configuration is provided by the Configuration Admin
>   service as a factory configuration with the following
>   properties:
>
>         bundle.symbolic.name
>         bundle.version (optional, defaults to any version)
>         count (optional, defaults to 1)
>         clazz (required)
>         filter (optional, defaults to "no filter")
>
>  * The SlingMainServlet registers a ManagedServiceFactory
>   listening for these configurations and maintains an
>   internal "state machine". This registration can be done
>   in the SlingMainServlet.activate method (and deregistration
>   in the SlingMainServlet.deactivate method)....

Would that allow for the bundle that provides the repository to
augment that config synchronously? i.e. SlingMainServlet receives the
configs before the repository bundle's activate() method returns, so
that SlingMainServlet considers system not ready immediately.

Scenario, to clarify:
1. SlingMainServlet not ready, repository missing
2. bundle that provides SlingRepository starts
3. bundle activator adds a number of configs as you describe
4. Later, SlingRepository service becomes available, SlingMainServlet
must already have the list of additional configs, or it might return
ready until it receives those

I'm not sure how much the ConfigurationAdmin async stuff influences
this, if we can guarantee 4. I'm fine with what you suggest.

>
>  * The implementation is part of the Sling Engine bundle
>   and is private to the Engine bundle.

ok

>
>  * The SlingMainServlet uses a simple method:
>       boolean isSystemReady()
>   conveying the state. The method should a non-readyness
>   reason. The SlingMainServlet will just send back 503
>   (or 404 ?) if not ready.

ok

>
>  * The internal implementation may be registered as a
>   Web Console plugin (or Configuration Printer) to provide
>   administrators with:
>
>      * details about the system status
>      * configuration form to easily manage the
>        configuration (maybe leveraging the Configuration
>        Admin support of the Web Console similar to how
>        the Commons Log bundle does it on the "Sling Log
>        Support" page.
>

ok

>  * Using JCR Install, FileInstall, the Web Console, or other
>   means of providing configuraiton, administrators may "fill"
>   the requirements list

ok

>
> Finally the SystemStatus interface is deprecated and the systemstatus
> bundle is removed (or moved to some attic location).

ok, we can probably remove it, after a vote to make sure no one requires it.

Thanks,
-Bertrand

Re: New proposal for SLING-490: ServiceWatchdog service in the sling engine bundle

Posted by Felix Meschberger <fm...@gmail.com>.
Hi,

Thanks for taking this up again.

But I have some concerns about the proposed implementation:

 * Returning a formatted string sounds wrong
 * We have to define public API, which is not used all
   outside of Engine, except for registering something
 * We have an issue of where to implement this thing..

I am considering the following issues:

 * The decision of whether a system is to be considered
   ready or not is mainly an administrative task
   (rather than a development time decision), we should place
   the administrator into a position to be able to configure
   this thing.
 * The SlingMainServlet is -- inside of Sling -- the only
   party really intereted in some state. Thus introduction of
   an externally visible API should probably be prevented
 * The parameters to the proposed addRequiredServices method
   makes up for a configuration. The method may be called
   multiple times with different values.
 * We may choose to provide data stored in the repository.

So, here is my proposal:

 * The configuration is provided by the Configuration Admin
   service as a factory configuration with the following
   properties:

         bundle.symbolic.name
         bundle.version (optional, defaults to any version)
         count (optional, defaults to 1)
         clazz (required)
         filter (optional, defaults to "no filter")

 * The SlingMainServlet registers a ManagedServiceFactory
   listening for these configurations and maintains an
   internal "state machine". This registration can be done
   in the SlingMainServlet.activate method (and deregistration
   in the SlingMainServlet.deactivate method).

 * The implementation is part of the Sling Engine bundle
   and is private to the Engine bundle.

 * The SlingMainServlet uses a simple method:
       boolean isSystemReady()
   conveying the state. The method should a non-readyness
   reason. The SlingMainServlet will just send back 503
   (or 404 ?) if not ready.

 * The internal implementation may be registered as a
   Web Console plugin (or Configuration Printer) to provide
   administrators with:

      * details about the system status
      * configuration form to easily manage the
        configuration (maybe leveraging the Configuration
        Admin support of the Web Console similar to how
        the Commons Log bundle does it on the "Sling Log
        Support" page.

 * Using JCR Install, FileInstall, the Web Console, or other
   means of providing configuraiton, administrators may "fill"
   the requirements list

Finally the SystemStatus interface is deprecated and the systemstatus
bundle is removed (or moved to some attic location).

WDYT ?

Regards
Felix

On 15.02.2010 17:01, Bertrand Delacretaz wrote:
> Hi,
> 
> Here's a new proposal for SLING-490, for a service that helps find out
> when a Sling system is ready to accept requests after startup.
> 
> Last discussion (http://markmail.org/thread/4bwmuwj6qnytmrfw) provided
> some good ideas, but I think this is much better, with low coupling
> and a possibility for bundles to declare additional required services
> before they become active, making it easier to have a well defined
> startup behavior.
> 
> The idea is to add an implementation of the ServiceWatchdog interface
> shown below, to the sling engine bundle.
> See details of the ServiceWatchdog interface below.
> 
> The sling engine bundle activator calls
> ServiceWatchdog.addRequiredServices based on configuration values read
> from BundleContext.getProperty, useful for repository-less setups.
> 
> The SlingMainServlet calls ServiceWatchdog.getMissingServices(), and
> returns HTTP status 503 if that's not null. That's the only place
> where this info is used by Sling itself.
> 
> As soon as the repository becomes available, before making it
> available as a SlingRepository service, the AbstractSlingRepository
> reads an optional list of additional required services from a
> well-known location in the repository, under /system/required-services
> for example,
> 
> I think this solves our previous concerns w.r.t possible race
> conditions at startup depending on which configuration mechanisms are
> used: client bundles are free to get the "required services" info from
> wherever makes sense for them, and the ServiceWatchdog reacts
> immediately to addRequiredServices calls, by clearing its internal
> state to force it to be recomputed on the next getMissingServices
> call.
> 
> The ServiceWatchdog implementation listens to service events and
> bundle events, to recompute the list of missing services when needed,
> and caches that info as long as no such events are received.
> 
> WDYT?
> 
> -Bertrand
> 
> 
> 
> /** Service that watches a specified set of services,
>  *  to check that they are all present.
>  */
> public interface ServiceWatchdog {
> 	/**	True if all specified services are present.
> 	 * 	That info is cached, so calling this is cheap
> 	 * 	unless relevant services and/or bundles events
> 	 * 	have been received, causing this to be recomputed.
> 	 *
> 	 *	@return null if all required services are present.
> 	 *		If services are missing, returns a formatted
> 	 *		string like
> 	 *		<pre>
> 	 *		ID:COUNT:CLAZZ:FILTER
> 	 *		ID:COUNT:CLAZZ:FILTER
> 	 *		...
> 	 *		</pre>
> 	 *		Where each ID:CLAZZ:FILTER line indicates a set of
> 	 *		services registered with {@link addRequiredServices)
> 	 *		for which BundleContext.getServiceReferences does not
> 	 *		return the expected number of services.
> 	 *	    	
> 	 */
> 	String getMissingServices();
> 	
> 	/**	Add one or several services to the list of services to watch.
> 	 * 	The watchdog calls BundleContext.getServiceReferences with
> 	 * 	the specified parameters to find out if the corresponding
> 	 * 	services are present.
> 	 *
> 	 * 	@param bundleId clazz and filter are tied to this bundle,
> 	 * 		if it is stopped or uninstalled, the corresponding
> 	 * 		clazz/filter values are removed from our list.
> 	 * 	@param count expected size of the array returned by
> 	 * 		BundleContext.getServiceReferences
> 	 * 	@param clazz used to call BundleContext.getServiceReferences
> 	 * 	@param filter used to call BundleContext.getServiceReferences
> 	 */
> 	void addRequiredServices(long bundleId, int count, String clazz,
> String filter);
> }
> 

Re: New proposal for SLING-490: ServiceWatchdog service in the sling engine bundle

Posted by Ian Boston <ie...@tfd.co.uk>.
On 15 Feb 2010, at 16:01, Bertrand Delacretaz wrote:

> WDYT?

Makes a lot of sense to me, 
Is there any service version in the list of required services ?

Ian