Similar to whats being discussed here is wrapped up in something called
associations in Rio.
Associations are a way to declare that a service uses (has an association to)
another service. Associations define a usage model for services in and across
architectures/deployments. Associations can be used either at deployment time
to assist in how a service get created in the context of the service(s) it is
associated to, or to wire-up distributed services, injected service references
into the declaring service.
Associations are declared in service deployment configuration, and if they have
been declared with the 'property' attribute, discovered services will be
injected into your service using an IoC approach. Based on the setter method's
signature, the injection type differs.
Given the examples below:
public void setFoos(Iterable<Foo> foos) {
this.foos = foos;
}
public void setFooAssociation(Association<Foo> foo) {
this.foo = foo;
}
public void setFoo(Foo foo) {
this.foo = foo;
}
If the injection point is the the last approach, Rio generates a client-side
proxy and *wraps* discovered associated service instances with a service
selection policy. The service selection strategy provides a way to determine
how services in the collection of discovered services are invoked. The current
service selection strategies are fail-over, round-robin and utilization (note
all service selection strategies will also prefer local services over remote
services).
• The Fail-Over strategy will invoke the first service in it's collection for
each method invocation until that service is no longer reachable. If the
associated service is unavailable, the fail-over strategy invokes the next
service in it's list.
• The Round Robin strategy alternates selection of services from the
association, alternating the selection of associated services using a
round-robin approach.
• The Utilization strategy is a round-robin selector that selects services
running on compute resources whose system resources are not depleted. System
resource depletion is determined by org.rioproject.system.MeasuredResource
provided as part of the org.rioproject.system.ComputeResourceUtilization object
returned as part of the deployment map. If any of a Cybernode's resources are
depleted, the service hosted in that Cybernode will not be invoked. This is of
particular use in cases where out of memory conditions may occur. Using the
utilization strategy a service running in a memory constrained Cybernode will
not be invoked until the JVM performs garbage collection and memory is
reclaimed.
Associations can be injected in a lazy or eager mode. Lazy injection is the
default, and injection occurs when a service is discovered. Eager injection
occurs immediately, even if there are no discovered services.
Associations must also deal with proxy failure modes. In a typical distributed
environment, if there are no discovered (available) services and a remote
method invocation is attempted on a service, a RemoteException is thrown. This
seems to make sense, although a better approach may be in order. Perhaps the
dynamic proxy can either wait until a service is discovered to make the
invocation, or provide at least a retry or timeout. It would seem that the
invoking client would need to do this in any case, and from a coding point of
view this behavior would be in the generated proxy, not in the application code.
The difference here is in a fail-fast approach, service invocation will fail in
an immediate and visible way, allowing the caller to be notified immediately
that something is wrong. In our context here, we would not immediately raise
the RemoteException (at least not right away), we would go onto the next
service. We would fail-fast if there are no services available. In association
terminology, the association would be broken.
With a fail-safe approach, we would want to constrain the notification that no
services are available (as opposed to failing fast by throwing a
RemoteException) in a managed way having the association proxy retry for a
certain period of time. In this case the fail-safe mode would have the caller
blocking on the service's remote method invocation until a service becomes
available, or until the retry logic exhausts itself. If the retries are
exhausted and there are still no available services, a RemoteException will be
thrown.
On Feb 16, 2010, at 1126AM, Christopher Dolan wrote:
> Tom's technique below is nice for automatic failover. Just for a point
> of reference, I'll describe the hot-standby approach we've taken at
> Avid.
>
> * Declare that your IFooService is an IRedundantService
> * The IFooService instances in the group discover each other and hold
> an election
> * The winner calls joinMgr.modifyAttributes() to mark itself as primary
> * The IFooService instances ping each other and if any one stops
> responding, another election is triggered
> * Clients search for the IFooService that is marked primary=true and
> talk only to it
>
> Limitations of this approach:
> * need for IFooService instances to inter-communicate
> * moments during election when there is no primary
> * rare partial-disconnect conditions where you get two primaries
>
> Wins of this approach:
> * election protocol is entirely up to the IFooServices, no client logic
> except to trust the Entry that says primary=true
> * only one primary at a time
> * the IFooService instances are already in contact, so adding state
> synchronization requires little extra infrastructure
>
> Good-and-bad aspects:
> * clients can decide how to handle the no-primary case themselves.
> More code, but more control too.
>
>
> I'd love to hear comments/criticisms of our approach, and if anyone has
> implemented something similar.
>
> Chris
>
> -----Original Message-----
> From: Tom Hobbs [mailto:[email protected]]
> Sent: Tuesday, February 09, 2010 4:21 AM
> To: [email protected]
> Subject: Service Wrapper Example
>
> Hi,
>
> I mentioned in another thread that I had come across code which provides
> service fail over and auto-rediscovery. I've posted details of the kind
> of
> code that was used to (note this has been reinvented in my head just now
> and
> only loosely tested);
>
> http://wiki.apache.org/river/AutomaticServiceReplacement
>
> I hope that someone finds it useful and/or interesting.
>
> It's important to note that in the interests of simplicity the
> ServiceWrapper class in the article is explicitly linked to the dummy
> service described. Obviously using more reflection magic it's possible
> to
> remove this linkage so that ServiceWrapper can wrap any service you like
> and
> it's invoke method would invoke the method supplied to it, rather than
> the
> only method available in the dummy article.
>
> Thanks to Jukka for his Wiki account suggestion.
>
> Enjoy,
>
> Tom