Service Type
- AbstratService
- CompositeService
Service Example
class Agent {
private final int id;
public Agent(int id) {
this.id = id;
}
// hashCode and equals method must be implemented if the object is used in HashMap as key or HashSet.
@Override
public int hashCode() {
return id;
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (obj == null) {
return false;
} else if (this.getClass() != obj.getClass()) {
return false;
} else {
Agent other = (Agent) obj;
return this.id == other.id;
}
}
@Override
public String toString() {
return "Agent: " + id;
}
}
Service class
class AgentManager extends AbstractService {
private static final Log LOG = LogFactory.getLog(AgentManager.class);
private int expireInterval;
private int monitorInterval;
private Thread checkerThread;
private boolean stopped = false;
private Map<Agent, Long> running;
public AgentManager() {
super("AgentManager");
}
@Override
protected void serviceInit(Configuration conf) throws Exception {
super.serviceInit(conf);
int expireIntvl = conf.getInt("com.baidu.dscheduler.agent.expire.ms",
1000 * 60 * 10);
//need some sanity check
this.expireInterval = expireIntvl;
this.monitorInterval = expireInterval / 3;
this.checkerThread = new Thread(new PingChecker());
this.checkerThread.setName("Ping Checker");
this.checkerThread.setDaemon(true);
}
@Override
protected void serviceStart() throws Exception {
super.serviceStart();
this.checkerThread.start();
}
@Override
protected void serviceStop() throws Exception {
stopped = true;
checkerThread.interrupt();
super.serviceStop();
}
private class PingChecker implements Runnable {
private PingChecker() {
}
public void run() {
while (!AgentManager.this.stopped && !Thread.currentThread().isInterrupted()) {
synchronized (AgentManager.this) {
Iterator<Map.Entry<Agent, Long>> iterator = AgentManager.this.running.entrySet().iterator();
long currentTime = System.currentTimeMillis();
while (true) {
if (!iterator.hasNext()) {
break;
}
Map.Entry<Agent, Long> entry = (Map.Entry) iterator.next();
if (currentTime > ((Long) entry.getValue()).longValue() + (long) AgentManager.this.expireInterval) {
iterator.remove();
//AgentManager.this.expire(entry.getKey());
AgentManager.LOG.info("Expired:" + entry.getKey().toString() + " Timed out after " + AgentManager.this.expireInterval / 1000 + " secs");
}
}
}
try {
Thread.sleep(AgentManager.this.monitorInterval);
continue;
} catch (InterruptedException e) {
AgentManager.this.LOG.info( AgentManager.this.getName() + " thread interrupted");
}
}
}
}
}
Test case
public class ServiceTest {
@Test
public void basicTest() {
Configuration conf = new Configuration(false);
//conf.addResource();
AgentManager agentManager = new AgentManager();
System.out.println("agentManager status after created: " + agentManager.getServiceState());
agentManager.init(conf);
System.out.println("agentManager status after instantiated: " + agentManager.getServiceState());
agentManager.start();
System.out.println("agentManager status after start: " + agentManager.getServiceState());
agentManager.stop();
System.out.println("agentManager status after stop: " + agentManager.getServiceState());
}
@Test
public void testStateChangeListener() {
Configuration conf = new Configuration(false);
//conf.addResource();
AgentManager agentManager = new AgentManager();
agentManager.registerServiceListener(new ServiceStateChangeListener() {
@Override
public void stateChanged(Service service) {
System.out.println("The state of service "
+ service.getName()
+ " changed to :"
+ service.getServiceState());
}
});
System.out.println("agentManager status after created: " + agentManager.getServiceState());
agentManager.init(conf);
System.out.println("agentManager status after instantiated: " + agentManager.getServiceState());
agentManager.start();
System.out.println("agentManager status after start: " + agentManager.getServiceState());
agentManager.stop();
System.out.println("agentManager status after stop: " + agentManager.getServiceState());
}
}
Composite Service
this.rmDispatcher = this.setupDispatcher();
this.addIfService(this.rmDispatcher);
this.adminService = this.createAdminService();
this.addService(this.adminService);
Service State
NOTINITED(0, "NOTINITED"), /** Constructed but not initialized */
INITED(1, "INITED"), /** Initialized but not started or stopped */
STARTED(2, "STARTED"), /** started and not stopped */
STOPPED(3, "STOPPED"); /** stopped. No further state transitions are permitted */
private static final boolean[][] statemap =
{
// uninited inited started stopped
/* uninited */ {false, true, false, true},
/* inited */ {false, true, true, true},
/* started */ {false, false, true, true},
/* stopped */ {false, false, false, true},
};
Why Use Service
- Make sure state change correctly, including concurrent call service.{init, start, stop} method.
@Override
public void init(Configuration conf) {
if (conf == null) {
throw new ServiceStateException("Cannot initialize service "
+ getName() + ": null configuration");
}
if (isInState(STATE.INITED)) {
return;
}
synchronized (stateChangeLock) {
if (enterState(STATE.INITED) != STATE.INITED) {
setConfig(conf);
try {
serviceInit(config);
if (isInState(STATE.INITED)) {
//if the service ended up here during init,
//notify the listeners
notifyListeners();
}
} catch (Exception e) {
noteFailure(e);
ServiceOperations.stopQuietly(LOG, this);
throw ServiceStateException.convert(e);
}
}
}
}
Test case:
@Test (expected = org.apache.hadoop.service.ServiceStateException.class)
public void testRestart() {
Configuration conf = new Configuration(false);
//conf.addResource();
AgentManager agentManager = new AgentManager();
System.out.println("agentManager status after created: " + agentManager.getServiceState());
agentManager.init(conf);
System.out.println("agentManager status after instantiated: " + agentManager.getServiceState());
agentManager.start();
System.out.println("agentManager status after start: " + agentManager.getServiceState());
agentManager.stop();
System.out.println("agentManager status after stop: " + agentManager.getServiceState());
agentManager.start();
}
2. Eliminate the need to copy common code.
- common code will be in different services .
- Composite service needs all the inner service start or stop.
public void start() {
service1.start();
service2.start();
service3.start();
...
}
Use Context to get various service
If we have many services, how can we get the one needed.
The answer is use a context object and pass it every where.
Take RMContext as an example:
RMContext has only one instance in the system.
ContainerAllocationExpirer getContainerAllocationExpirer();
DelegationTokenRenewer getDelegationTokenRenewer();
AMRMTokenSecretManager getAMRMTokenSecretManager();
RMContainerTokenSecretManager getContainerTokenSecretManager();
NMTokenSecretManagerInRM getNMTokenSecretManager();
ResourceScheduler getScheduler();
NodesListManager getNodesListManager();
ClientToAMTokenSecretManagerInRM getClientToAMTokenSecretManager();
AdminService getRMAdminService();
ClientRMService getClientRMService();
ApplicationMasterService getApplicationMasterService();
ResourceTrackerService getResourceTrackerService();
void setClientRMService(ClientRMService var1);