Reset a bureau if its launcher does not connect back in a timely fashion

git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@5266 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Jamie Doornbos
2008-07-25 22:58:03 +00:00
parent 4a5f474183
commit 4fab6bb71a
@@ -30,6 +30,8 @@ import com.google.common.collect.Sets;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import com.samskivert.util.Interval;
import com.samskivert.util.RunQueue;
import com.samskivert.util.StringUtil; import com.samskivert.util.StringUtil;
import com.samskivert.util.Invoker; import com.samskivert.util.Invoker;
import com.samskivert.util.ProcessLogger; import com.samskivert.util.ProcessLogger;
@@ -166,7 +168,7 @@ public class BureauRegistry
/** /**
* Registers a command generator for a given type. When an agent is started and no bureaus are * Registers a command generator for a given type. When an agent is started and no bureaus are
* running, the <code>bureauType</code> is used to determine the <code>CommandGenerator</code> * running, the <code>bureauType</code> is used to determine the <code>CommandGenerator</code>
* instance to call. * instance to call. The registry will wait indefinitely for the bureau to connect back.
* @param bureauType the type of bureau that will be launched * @param bureauType the type of bureau that will be launched
* @param cmdGenerator the generator to be used for bureaus of <code>bureauType</code> * @param cmdGenerator the generator to be used for bureaus of <code>bureauType</code>
*/ */
@@ -174,6 +176,24 @@ public class BureauRegistry
String bureauType, String bureauType,
final CommandGenerator cmdGenerator) final CommandGenerator cmdGenerator)
{ {
}
/**
* Registers a command generator for a given type. When an agent is started and no bureaus are
* running, the <code>bureauType</code> is used to determine the <code>CommandGenerator</code>
* instance to call. If the launched bureau does not connect within the given number of
* milliseconds, it will be logged as an error and future attempts to launch the bureau
* will try launching the command again.
* @param bureauType the type of bureau that will be launched
* @param cmdGenerator the generator to be used for bureaus of <code>bureauType</code>
* @param timeout milliseconds to wait for the bureau or 0 to wait forever
*/
public void setCommandGenerator (
String bureauType,
final CommandGenerator cmdGenerator,
int timeout)
{
setLauncher(bureauType, new Launcher() { setLauncher(bureauType, new Launcher() {
public void launchBureau (String bureauId, String token) public void launchBureau (String bureauId, String token)
throws IOException { throws IOException {
@@ -189,24 +209,40 @@ public class BureauRegistry
public String toString () { public String toString () {
return "DefaultLauncher for " + cmdGenerator; return "DefaultLauncher for " + cmdGenerator;
} }
}); }, timeout);
} }
/** /**
* Registers a launcher for a given type. When an agent is started and no bureaus are * Registers a launcher for a given type. When an agent is started and no bureaus are
* running, the <code>bureauType</code> is used to determine the <code>Launcher</code> * running, the <code>bureauType</code> is used to determine the <code>Launcher</code>
* instance to call. * instance to call. The registry will wait indefinitely for the launched bureau
* to connect back.
* @param bureauType the type of bureau that will be launched * @param bureauType the type of bureau that will be launched
* @param launcher the launcher to be used for bureaus of <code>bureauType</code> * @param launcher the launcher to be used for bureaus of <code>bureauType</code>
*/ */
public void setLauncher (String bureauType, Launcher launcher) public void setLauncher (String bureauType, Launcher launcher)
{
setLauncher(bureauType, launcher, 0);
}
/**
* Registers a launcher for a given type. When an agent is started and no bureaus are
* running, the <code>bureauType</code> is used to determine the <code>Launcher</code>
* instance to call. If the launched bureau does not connect within the given number of
* milliseconds, it will be logged as an error and future attempts to launch the bureau
* will invoke the <code>launch</code> method again.
* @param bureauType the type of bureau that will be launched
* @param launcher the launcher to be used for bureaus of <code>bureauType</code>
* @param timeout milliseconds to wait for the bureau or 0 to wait forever
*/
public void setLauncher (String bureauType, Launcher launcher, int timeout)
{ {
if (_launchers.get(bureauType) != null) { if (_launchers.get(bureauType) != null) {
log.warning("Launcher for type already exists", "type", bureauType); log.warning("Launcher for type already exists", "type", bureauType);
return; return;
} }
_launchers.put(bureauType, launcher); _launchers.put(bureauType, new LauncherEntry(launcher, timeout));
} }
/** /**
@@ -231,20 +267,20 @@ public class BureauRegistry
if (bureau == null) { if (bureau == null) {
Launcher launcher = _launchers.get(agent.bureauType); LauncherEntry launcherEntry = _launchers.get(agent.bureauType);
if (launcher == null) { if (launcherEntry == null) {
log.warning("Launcher not found", "agent", agent); log.warning("Launcher not found", "agent", agent);
return; return;
} }
log.info("Creating new bureau", "bureauId", agent.bureauId, "launcher", launcher); log.info("Creating new bureau", "bureauId", agent.bureauId, "launcher", launcherEntry);
bureau = new Bureau(); bureau = new Bureau();
bureau.bureauId = agent.bureauId; bureau.bureauId = agent.bureauId;
bureau.token = generateToken(bureau.bureauId); bureau.token = generateToken(bureau.bureauId);
bureau.launcher = launcher; bureau.launcherEntry = launcherEntry;
_invoker.postUnit(new LauncherUnit(bureau)); _invoker.postUnit(new LauncherUnit(bureau, _omgr));
_bureaus.put(agent.bureauId, bureau); _bureaus.put(agent.bureauId, bureau);
} }
@@ -525,16 +561,36 @@ public class BureauRegistry
System.currentTimeMillis() + "r" + Math.random(); System.currentTimeMillis() + "r" + Math.random();
return StringUtil.md5hex(tokenSource); return StringUtil.md5hex(tokenSource);
} }
/**
* Called by the launcher unit timeout time after launching.
* @param bureau bureau whose launch occurred
*/
protected void launchTimeoutExpired (Bureau bureau)
{
if (bureau.clientObj != null) {
// all's well, ignore
return;
}
if (!_bureaus.containsKey(bureau.bureauId)) {
// bureau has already managed to get destroyed before the launch timeout, ignore
return;
}
log.warning("Bureau failed to launch", "bureau", bureau);
_bureaus.remove(bureau.bureauId);
}
/** /**
* Invoker unit to launch a bureau's process, then assign the result on the main thread. * Invoker unit to launch a bureau's process, then assign the result on the main thread.
*/ */
protected static class LauncherUnit extends Invoker.Unit protected class LauncherUnit extends Invoker.Unit
{ {
LauncherUnit (Bureau bureau) LauncherUnit (Bureau bureau, RunQueue runQueue)
{ {
super("LauncherUnit for " + bureau + ": " + super("LauncherUnit for " + bureau + ": " +
StringUtil.toString(bureau.launcher)); StringUtil.toString(bureau.launcherEntry));
_bureau = bureau; _bureau = bureau;
} }
@@ -553,15 +609,41 @@ public class BureauRegistry
@Override @Override
public void handleResult () public void handleResult ()
{ {
int timeout = _bureau.launcherEntry.timeout;
if (timeout != 0) {
new Interval(_runQueue) {
public void expired () {
launchTimeoutExpired(_bureau);
}
}.schedule(timeout);
}
_bureau.launched = true; _bureau.launched = true;
_bureau.launcher = null; _bureau.launcherEntry = null;
log.info("Bureau launched", "bureau", _bureau); log.info("Bureau launched", "bureau", _bureau);
} }
protected Bureau _bureau; protected Bureau _bureau;
protected Process _result; protected Process _result;
protected RunQueue _runQueue;
} }
protected static class LauncherEntry
{
public Launcher launcher;
public int timeout;
public LauncherEntry (Launcher launcher, int timeout)
{
this.launcher = launcher;
this.timeout = timeout;
}
public String toString ()
{
return StringUtil.fieldsToString(this);
}
}
protected enum AgentState protected enum AgentState
{ {
// Not yet stated, waiting for bureau to ack // Not yet stated, waiting for bureau to ack
@@ -604,7 +686,7 @@ public class BureauRegistry
protected static class Bureau protected static class Bureau
{ {
// non-null once the bureau is scheduled but not yet kicked off // non-null once the bureau is scheduled but not yet kicked off
Launcher launcher; LauncherEntry launcherEntry;
// non-null once the bureau is kicked off // non-null once the bureau is kicked off
boolean launched; boolean launched;
@@ -636,7 +718,7 @@ public class BureauRegistry
} else { } else {
builder.append(clientObj.getOid()); builder.append(clientObj.getOid());
} }
builder.append(", launcher=").append(launcher); builder.append(", launcherEntry=").append(launcherEntry);
builder.append(", launched=").append(launched); builder.append(", launched=").append(launched);
builder.append(", totalAgents=").append(agentStates.size()); builder.append(", totalAgents=").append(agentStates.size());
agentSummary(builder.append(", ")).append("]"); agentSummary(builder.append(", ")).append("]");
@@ -674,11 +756,12 @@ public class BureauRegistry
void launch () void launch ()
throws IOException throws IOException
{ {
launcher.launchBureau(bureauId, token); launcherEntry.launcher.launchBureau(bureauId, token);
} }
} }
protected Map<String, Launcher> _launchers = Maps.newHashMap(); protected Map<String, LauncherEntry> _launchers = Maps.newHashMap();
protected Map<String, Bureau> _bureaus = Maps.newHashMap(); protected Map<String, Bureau> _bureaus = Maps.newHashMap();
@Inject protected RootDObjectManager _omgr; @Inject protected RootDObjectManager _omgr;