You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by de...@apache.org on 2018/04/17 17:24:52 UTC
svn commit: r1829373 - in /uima/uima-ducc/branches/reliable-ducc:
src/main/admin/ src/main/scripts/
uima-ducc-duccdocs/src/site/tex/duccbook/part4/admin/
Author: degenaro
Date: Tue Apr 17 17:24:51 2018
New Revision: 1829373
URL: http://svn.apache.org/viewvc?rev=1829373&view=rev
Log:
UIMA-5742 Reliable DUCC
- start/stop/kill broker only when ducc.broker.autostart = true
- start/stop/kill database only when ducc.database.autostart = true
- do not start/stop agents from backup head node
Modified:
uima/uima-ducc/branches/reliable-ducc/src/main/admin/check_ducc
uima/uima-ducc/branches/reliable-ducc/src/main/admin/ducc_head_mode.py
uima/uima-ducc/branches/reliable-ducc/src/main/admin/ducc_util.py
uima/uima-ducc/branches/reliable-ducc/src/main/admin/start_ducc
uima/uima-ducc/branches/reliable-ducc/src/main/admin/stop_ducc
uima/uima-ducc/branches/reliable-ducc/src/main/scripts/properties.py
uima/uima-ducc/branches/reliable-ducc/uima-ducc-duccdocs/src/site/tex/duccbook/part4/admin/admin-commands.tex
Modified: uima/uima-ducc/branches/reliable-ducc/src/main/admin/check_ducc
URL: http://svn.apache.org/viewvc/uima/uima-ducc/branches/reliable-ducc/src/main/admin/check_ducc?rev=1829373&r1=1829372&r2=1829373&view=diff
==============================================================================
--- uima/uima-ducc/branches/reliable-ducc/src/main/admin/check_ducc (original)
+++ uima/uima-ducc/branches/reliable-ducc/src/main/admin/check_ducc Tue Apr 17 17:24:51 2018
@@ -99,6 +99,10 @@ class CheckDucc(DuccUtil):
signal = self.kill_signal
+ if(self.is_reliable_backup()):
+ if ( component == 'agent' ):
+ continue
+
if ( component == 'orchestrator' ):
component = 'or'
@@ -116,18 +120,21 @@ class CheckDucc(DuccUtil):
else:
messages.append((spacer, 'Killing (' + signal + ')', process_id))
self.kill_process(node, proc, signal)
- self.pids.delete(pid)
+ if ( component == 'agent' ):
+ self.pids_agents.delete(pid)
+ else:
+ self.pids_daemons.delete(pid)
process_changes = True
else:
messages.append((spacer, 'Found', process_id))
full_name = component + '@' + node
if ( component == 'agent' ):
- self.pids.put(full_name, pid)
-
- if ( component in self.default_components ):
- self.pids.put(full_name, pid)
- self.pids.put(component, full_name)
+ self.pids_agents.put(full_name, pid)
+ else:
+ if ( component in self.default_components ):
+ self.pids_daemons.put(full_name, pid)
+ self.pids_daemons.put(component, full_name)
else:
messages.append((spacer, 'no processes found.'))
@@ -172,6 +179,11 @@ class CheckDucc(DuccUtil):
print ""
print " check_ducc -n ../resources/ducc.nodes"
print ""
+ print " For reliable DUCC agents will not be killed from backup head node. "
+ print ""
+ print " Broker will not be killed when ducc.broker.automanage = false. "
+ print " Database will not be killed when ducc.database.automanage = false. "
+ print ""
print "Options:"
print " -n --nodelist nodefile"
print " Check for agents on the nodes in nodefile. This option may be specified multiple time"
@@ -203,7 +215,7 @@ class CheckDucc(DuccUtil):
print " changes."
print ""
print " -x localdate"
- print " Validate the local installation, called via ssh usually. The date is the dat on the calling machine."
+ print " Validate the local installation, called via ssh usually. The date is the date on the calling machine."
print ""
print " --nothreading"
print " Disable multithreaded operation if it would otherwise be used"
@@ -306,9 +318,12 @@ class CheckDucc(DuccUtil):
self.verify_database()
# init the PID file
- self.pids = Properties()
- self.pids.load_if_exists(self.pid_file)
-
+ if(not self.is_reliable_backup()):
+ self.pids_agents = Properties()
+ self.pids_agents.load_if_exists(self.pid_file_agents)
+ self.pids_daemons = Properties()
+ self.pids_daemons.load_if_exists(self.pid_file_daemons)
+
# read the nodelists
if ( len(nodefiles) == 0 ):
nodefiles = self.default_nodefiles
@@ -376,17 +391,30 @@ class CheckDucc(DuccUtil):
self.threadpool.quit()
if ( self.kill_signal != None ):
- print 'Stopping broker'
- self.stop_broker()
- print 'Stopping database'
- self.db_stop()
-
- if ( len(self.pids) == 0):
- if ( os.path.exists(self.pid_file) ):
- os.remove(self.pid_file)
+ if(self.automanage_broker):
+ print 'Stopping broker'
+ self.stop_broker()
+ else:
+ print 'Not stopping broker - not automanaged'
+ if(self.automanage_database):
+ print 'Stopping database'
+ self.db_stop()
+ else:
+ print 'Not stopping database - not automanaged'
+
+ if(not self.is_reliable_backup()):
+ if ( len(self.pids_agents) == 0):
+ if ( os.path.exists(self.pid_file_agents) ):
+ os.remove(self.pid_file_agents)
+ elif (process_changes or redo_pids):
+ self.pids_agents.write(self.pid_file_agents)
+
+ if ( len(self.pids_daemons) == 0):
+ if ( os.path.exists(self.pid_file_daemons) ):
+ os.remove(self.pid_file_daemons)
elif (process_changes or redo_pids):
- self.pids.write(self.pid_file)
-
+ self.pids_daemons.write(self.pid_file_daemons)
+
if __name__ == "__main__":
checker = CheckDucc()
checker.main(sys.argv[1:])
Modified: uima/uima-ducc/branches/reliable-ducc/src/main/admin/ducc_head_mode.py
URL: http://svn.apache.org/viewvc/uima/uima-ducc/branches/reliable-ducc/src/main/admin/ducc_head_mode.py?rev=1829373&r1=1829372&r2=1829373&view=diff
==============================================================================
--- uima/uima-ducc/branches/reliable-ducc/src/main/admin/ducc_head_mode.py (original)
+++ uima/uima-ducc/branches/reliable-ducc/src/main/admin/ducc_head_mode.py Tue Apr 17 17:24:51 2018
@@ -31,47 +31,9 @@ class DuccHeadMode(DuccUtil):
# operation: look in ducc.properties for relevant keywords
# and employ linux commands to determine if system
# has matching configured virtual ip address
-
- debug_flag = False
- def debug(self,text):
- if(self.debug_flag):
- print(text)
-
- keepalivd_conf = '/etc/keepalived/keepalived.conf'
-
- # eligible when keepalived config comprises the ip
- def is_reliable_eligible(self, ip):
- retVal = False
- if ( os.path.exists(self.keepalivd_conf) ):
- with open(self.keepalivd_conf) as f:
- for line in f:
- if ip in line:
- retVal = True
- break
- return retVal
-
- # master when current node keepalived answers for head node ip
- # backup when current node keepalived does not answer for head ip, but is capable in config
- # unspecified otherwise
def main(self):
- result = 'unspecified'
- try:
- ducc_head = self.ducc_properties.get('ducc.head')
- head_ip = self.get_ip_address(ducc_head)
- if(self.is_reliable_eligible(head_ip)):
- text = 'cmd: ', '/sbin/ip', 'addr', 'list'
- self.debug(text)
- p = subprocess.Popen(['/sbin/ip', 'addr', 'list'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- output, err = p.communicate()
- text = "output: "+output
- self.debug(text)
- if(head_ip in output):
- result = 'master'
- else:
- result = 'backup'
- except Exception as e:
- print e
+ result = self.get_reliable_state()
print result
if __name__ == '__main__':
Modified: uima/uima-ducc/branches/reliable-ducc/src/main/admin/ducc_util.py
URL: http://svn.apache.org/viewvc/uima/uima-ducc/branches/reliable-ducc/src/main/admin/ducc_util.py?rev=1829373&r1=1829372&r2=1829373&view=diff
==============================================================================
--- uima/uima-ducc/branches/reliable-ducc/src/main/admin/ducc_util.py (original)
+++ uima/uima-ducc/branches/reliable-ducc/src/main/admin/ducc_util.py Tue Apr 17 17:24:51 2018
@@ -583,6 +583,7 @@ class DuccUtil(DuccBase):
# transform hostname into ip address
def get_ip_address(self,hostname):
+ label = 'get_ip_address'
result = None
try:
p = subprocess.Popen(['/usr/bin/nslookup', hostname], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@@ -602,7 +603,7 @@ class DuccUtil(DuccBase):
name = t1
except Exception as e:
print e
- debug('ip_address: ', str(result))
+ debug(label, str(result))
return result
# get all possible hostnames & ip addresses for a head node
@@ -1192,6 +1193,46 @@ class DuccUtil(DuccBase):
return False
return True
+ keepalivd_conf = '/etc/keepalived/keepalived.conf'
+
+ # eligible when keepalived config comprises the ip
+ def is_reliable_eligible(self, ip):
+ retVal = False
+ if ( os.path.exists(self.keepalivd_conf) ):
+ with open(self.keepalivd_conf) as f:
+ for line in f:
+ if ip in line:
+ retVal = True
+ break
+ return retVal
+
+ # master when current node keepalived answers for head node ip
+ # backup when current node keepalived does not answer for head ip, but is capable in config
+ # unspecified otherwise
+ def get_reliable_state(self):
+ label = 'get_reliable_state'
+ result = 'unspecified'
+ try:
+ ducc_head = self.ducc_properties.get('ducc.head')
+ head_ip = self.get_ip_address(ducc_head)
+ if(self.is_reliable_eligible(head_ip)):
+ text = 'cmd: ', '/sbin/ip', 'addr', 'list'
+ debug(label, text)
+ p = subprocess.Popen(['/sbin/ip', 'addr', 'list'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ output, err = p.communicate()
+ text = "output: "+output
+ debug(label, text)
+ if(head_ip in output):
+ result = 'master'
+ else:
+ result = 'backup'
+ except Exception as e:
+ print e
+ return result
+
+ def is_reliable_backup(self):
+ return self.get_reliable_state() == 'backup'
+
def __init__(self, merge=False):
global use_threading
DuccBase.__init__(self, merge)
@@ -1209,7 +1250,7 @@ class DuccUtil(DuccBase):
if ( self.localhost == self.ducc_properties.get("ducc.head")):
self.is_ducc_head = True
- os.environ['DUCC_NODENAME'] = self.localhost # to match java code's implicit propery so script and java match
+ os.environ['DUCC_NODENAME'] = self.localhost # to match java code's implicit property so script and java match
dbhost = self.ducc_properties.get('ducc.database.host')
if ( dbhost == None ):
@@ -1225,7 +1266,8 @@ class DuccUtil(DuccBase):
self.db_pidfile = dir_db_state+ '/cassandra.pid'
self.db_logfile = dir_db_logs + '/cassandra.console'
- self.pid_file = self.DUCC_HOME + '/state/ducc.pids'
+ self.pid_file_agents = self.DUCC_HOME + '/state/agents/ducc.pids'
+ self.pid_file_daemons = self.DUCC_HOME + '/state/daemons/'+self.get_node_name()+'/ducc.pids'
self.set_classpath()
self.os_pagesize = self.get_os_pagesize()
self.update_properties()
Modified: uima/uima-ducc/branches/reliable-ducc/src/main/admin/start_ducc
URL: http://svn.apache.org/viewvc/uima/uima-ducc/branches/reliable-ducc/src/main/admin/start_ducc?rev=1829373&r1=1829372&r2=1829373&view=diff
==============================================================================
--- uima/uima-ducc/branches/reliable-ducc/src/main/admin/start_ducc (original)
+++ uima/uima-ducc/branches/reliable-ducc/src/main/admin/start_ducc Tue Apr 17 17:24:51 2018
@@ -52,7 +52,7 @@ class StartDucc(DuccUtil):
if ( line.startswith('PID') ):
toks = line.split(' ') # get the PID
print "Broker on", broker_host, 'PID', toks[1]
- self.pids.put('broker@' + broker_host, toks[1])
+ self.pids_daemons.put('broker@' + broker_host, toks[1])
lines.close()
break
@@ -103,7 +103,7 @@ class StartDucc(DuccUtil):
if ( line.startswith('PID') ):
toks = line.split(' ') # get the PID
msgs.append((' PID', toks[1]))
- self.pids.put(com + '@' + node, toks[1])
+ self.pids_daemons.put(com + '@' + node, toks[1])
lines.close()
break
if ( line.startswith('WARN') ):
@@ -111,7 +111,7 @@ class StartDucc(DuccUtil):
if ( com in self.default_components ): # tracks where the management processes are
self.pidlock.acquire()
- self.pids.put(com, com + '@' + node)
+ self.pids_daemons.put(com, com + '@' + node)
self.pidlock.release()
return msgs
@@ -131,7 +131,7 @@ class StartDucc(DuccUtil):
toks = line.split(' ')
pid = toks[1]
self.pidlock.acquire()
- self.pids.put('agent@' + host, pid)
+ self.pids_agents.put('agent@' + host, pid)
self.pidlock.release()
lines.close()
@@ -172,6 +172,11 @@ class StartDucc(DuccUtil):
print " If no options are given, all DUCC processes are started, using the default"
print " nodelist, DUCC_HOME/resources/ducc.nodes. "
print ""
+ print " For reliable DUCC agents will not be started from backup head node. "
+ print ""
+ print " Broker will not be started when ducc.broker.automanage = false. "
+ print " Database will not be started when ducc.database.automanage = false. "
+ print ""
print "Options:"
print " -n --nodelist nodefile"
print " Start agents on the nodes in the nodefile. Multiple nodefiles may be specified:"
@@ -242,8 +247,11 @@ class StartDucc(DuccUtil):
nodefiles = []
components = []
or_parms = self.ducc_properties.get('ducc.orchestrator.start.type')
- self.pids = Properties()
- self.pids.load_if_exists(self.pid_file)
+ if(not self.is_reliable_backup()):
+ self.pids_agents = Properties()
+ self.pids_agents.load_if_exists(self.pid_file_agents)
+ self.pids_daemons = Properties()
+ self.pids_daemons.load_if_exists(self.pid_file_daemons)
try:
opts, args = getopt.getopt(argv, 'c:mn:sh?v', ['component=', 'help', 'nodelist=', 'cold', 'warm', 'nothreading'])
@@ -372,16 +380,17 @@ class StartDucc(DuccUtil):
sys.exit(1)
# give 'or' a small head start
time.sleep(2)
-
- for (nodefile, nodelist) in nodes.items():
- print '********** Starting agents from file', nodefile
- try:
- for node in nodelist:
- self.threadpool.invoke(self.start_one_agent, node)
- except:
- self.threadpool.quit()
- print sys.exc_info()[0], "DUCC may not be started correctly."
- sys.exit(1)
+
+ if(not self.is_reliable_backup()):
+ for (nodefile, nodelist) in nodes.items():
+ print '********** Starting agents from file', nodefile
+ try:
+ for node in nodelist:
+ self.threadpool.invoke(self.start_one_agent, node)
+ except:
+ self.threadpool.quit()
+ print sys.exc_info()[0], "DUCC may not be started correctly."
+ sys.exit(1)
if ( len(components) != 0 ):
print 'Starting', or_parms
@@ -400,8 +409,11 @@ class StartDucc(DuccUtil):
self.threadpool.quit()
- if ( len(self.pids) > 0 ):
- self.pids.write(self.pid_file)
+ if(not self.is_reliable_backup()):
+ if ( len(self.pids_agents) > 0 ):
+ self.pids_agents.write(self.pid_file_agents)
+ if ( len(self.pids_daemons) > 0 ):
+ self.pids_daemons.write(self.pid_file_daemons)
return
if __name__ == "__main__":
Modified: uima/uima-ducc/branches/reliable-ducc/src/main/admin/stop_ducc
URL: http://svn.apache.org/viewvc/uima/uima-ducc/branches/reliable-ducc/src/main/admin/stop_ducc?rev=1829373&r1=1829372&r2=1829373&view=diff
==============================================================================
--- uima/uima-ducc/branches/reliable-ducc/src/main/admin/stop_ducc (original)
+++ uima/uima-ducc/branches/reliable-ducc/src/main/admin/stop_ducc Tue Apr 17 17:24:51 2018
@@ -46,11 +46,18 @@ class StopDucc(DuccUtil):
# If it's an unqualified management component, we need to get it's qualified name
#
if ( component in self.default_components ):
- if ( self.pids.has_key(component) ):
- component = self.pids.get(component)
+ if( component == 'agent' ):
+ if ( self.pids_agents.has_key(component) ):
+ component = self.pids_agents.get(component)
+ else:
+ print 'Skipping', component, 'not in pids file.'
+ return
else:
- print 'Skipping', component, 'not in pids file.'
- return
+ if ( self.pids_daemons.has_key(component) ):
+ component = self.pids_daemons.get(component)
+ else:
+ print 'Skipping', component, 'not in pids file.'
+ return
#
# If the name is not qualified we've got a problem, everything in the pids file is qualified
@@ -63,11 +70,19 @@ class StopDucc(DuccUtil):
#
# If despite all that we can't find the pid, we need to run check_ducc
#
- if ( not self.pids.has_key(component) ):
- print "Cannot find PID for component", component, ". Run check_ducc -p to refresh PIDS and then rerun stop_ducc."
- return
-
- pid = self.pids.get(component)
+ if( com == 'agent' ):
+ if ( not self.pids_agents.has_key(component) ):
+ print "Cannot find PID for component", component, ". Run check_ducc -p to refresh PIDS and then rerun stop_ducc."
+ return
+ else:
+ pid = self.pids_agents.get(component)
+ else:
+ if ( not self.pids_daemons.has_key(component) ):
+ print "Cannot find PID for component", component, ". Run check_ducc -p to refresh PIDS and then rerun stop_ducc."
+ return
+ else:
+ pid = self.pids_daemons.get(component)
+
if ( force ):
print 'Stopping component', com, 'on node', target_node, 'with PID', pid, 'forcibly (kill -9)'
@@ -79,8 +94,12 @@ class StopDucc(DuccUtil):
self.nohup(['ssh', target_node, 'kill', '-INT', pid], False)
# clear the short name if it exists, and the long name
- self.pids.delete(com)
- self.pids.delete(component)
+ if( com == 'agent' ):
+ self.pids_agents.delete(com)
+ self.pids_agents.delete(component)
+ else:
+ self.pids_daemons.delete(com)
+ self.pids_daemons.delete(component)
def quiesce_agents(self, components, nodes):
@@ -106,7 +125,8 @@ class StopDucc(DuccUtil):
return
def stop_agents(self, node, force):
- self.stop_component('agent@' + node.strip(), force)
+ if(not self.is_reliable_backup()):
+ self.stop_component('agent@' + node.strip(), force)
def usage(self, msg):
if ( msg != None ):
@@ -115,6 +135,11 @@ class StopDucc(DuccUtil):
print 'stop_ducc [options]'
print ' If no options are given, this help screen is shown.'
print ''
+ print ' For reliable DUCC agents will not be stopped from backup head node. '
+ print ''
+ print ' Broker will not be stopped when ducc.broker.automanage = false. '
+ print ' Database will not be stopped when ducc.database.automanage = false. '
+ print ''
print 'Options:'
print ' -a --all'
print ' Stop all the DUCC processes, including agents and management processes.'
@@ -260,27 +285,30 @@ class StopDucc(DuccUtil):
print "Stopping database"
self.db_stop()
- if ( os.path.exists(self.pid_file) ):
- os.remove(self.pid_file)
+ if ( os.path.exists(self.pid_file_agents) ):
+ os.remove(self.pid_file_agents)
+ if ( os.path.exists(self.pid_file_daemons) ):
+ os.remove(self.pid_file_daemons)
return
else:
if ( len(nodefiles) == 0 ):
nodefiles = self.default_nodefiles
- self.pids = Properties()
+ self.pids_agents = Properties()
+ self.pids_daemons = Properties()
sc = set(components)
sb = set(['broker', 'db'])
read_pids = True
if ( sc.issubset(sb) ):
read_pids = False
-
# The broker and db do not set the pid file
if ( read_pids ):
try:
- self.pids.load(self.pid_file)
- pass
+ if(not self.is_reliable_backup()):
+ self.pids_agents.load(self.pid_file_agents)
+ self.pids_daemons.load(self.pid_file_daemons)
except PropertiesException, (inst):
print inst.msg
print ''
@@ -333,10 +361,15 @@ class StopDucc(DuccUtil):
self.stop_component(c, force)
if ( read_pids ):
- if ( len(self.pids) > 0 ):
- self.pids.write(self.pid_file)
+ if(not self.is_reliable_backup()):
+ if ( len(self.pids_agents) > 0 ):
+ self.pids_agents.write(self.pid_file_agents)
+ else:
+ os.remove(self.pid_file_agents)
+ if ( len(self.pids_daemons) > 0 ):
+ self.pids_daemons.write(self.pid_file_daemons)
else:
- os.remove(self.pid_file)
+ os.remove(self.pid_file_daemons)
return
Modified: uima/uima-ducc/branches/reliable-ducc/src/main/scripts/properties.py
URL: http://svn.apache.org/viewvc/uima/uima-ducc/branches/reliable-ducc/src/main/scripts/properties.py?rev=1829373&r1=1829372&r2=1829373&view=diff
==============================================================================
--- uima/uima-ducc/branches/reliable-ducc/src/main/scripts/properties.py (original)
+++ uima/uima-ducc/branches/reliable-ducc/src/main/scripts/properties.py Tue Apr 17 17:24:51 2018
@@ -213,11 +213,22 @@ class Properties:
if ( self.props.has_key(key) ):
del self.props[key]
self.keys.remove(key)
-
+
+ #
+ # make directories, if need be
+ #
+ def _makedirs(self, path):
+ try:
+ dir_path = path.rsplit('/',1)[0]
+ os.makedirs(dir_path)
+ except:
+ pass
+
#
# Write the has as a Java-like properties file
#
def write(self, propsfile):
+ self._makedirs(propsfile)
f = open(propsfile, 'w')
for k in self.keys:
p = self.props[k]
Modified: uima/uima-ducc/branches/reliable-ducc/uima-ducc-duccdocs/src/site/tex/duccbook/part4/admin/admin-commands.tex
URL: http://svn.apache.org/viewvc/uima/uima-ducc/branches/reliable-ducc/uima-ducc-duccdocs/src/site/tex/duccbook/part4/admin/admin-commands.tex?rev=1829373&r1=1829372&r2=1829373&view=diff
==============================================================================
--- uima/uima-ducc/branches/reliable-ducc/uima-ducc-duccdocs/src/site/tex/duccbook/part4/admin/admin-commands.tex (original)
+++ uima/uima-ducc/branches/reliable-ducc/uima-ducc-duccdocs/src/site/tex/duccbook/part4/admin/admin-commands.tex Tue Apr 17 17:24:51 2018
@@ -42,6 +42,13 @@
Services Manager, and Web Server on the local node.
\item Starts an agent process on every node named in the default node list.
\end{itemize}
+
+ Exceptions:
+ \begin{itemize}
+ \item When running reliable DUCC, agents are not started from any backup node.
+ \item When ducc.broker.autostart = false, the ActiveMQ server will not be started.
+ \item When ducc.database.autostart = false, the database will not be started.
+ \end{itemize}
\subsubsection{{\em Usage}}
@@ -144,13 +151,19 @@ start_ducc -c sm -c pm -c rm -c or@bj22
When {\em -a} is specified, the following actions are taken:
\begin{itemize}
\item Uses the ActiveMQ broker to broadcast a shutdown request to all
- DUCC compoments, other than the ActiveMQ broker itself, and the database.
+ DUCC components, other than the ActiveMQ broker itself, and the database.
\item Waits a bit, for all daemons to stop.
\item Stops the database.
\item Stops the ActiveMQ broker.
\end{itemize}
-
+ Exceptions:
+ \begin{itemize}
+ \item When running reliable DUCC, agents are not stopped from any backup node.
+ \item When ducc.broker.autostart = false, the ActiveMQ server will not be stopped.
+ \item When ducc.database.autostart = false, the database will not be stopped.
+ \end{itemize}
+
\subsubsection{\em Usage:}
\begin{description}
@@ -250,6 +263,13 @@ start_ducc -c rm
to do so. The difference is that stop\_ducc generally tries more gracefully stop processes.
check\_ducc is used as a last resort, or if a fast but graceless shutdown is desired.
+ Exceptions:
+ \begin{itemize}
+ \item When running reliable DUCC, agents are not killed from any backup node.
+ \item When ducc.broker.autostart = false, the ActiveMQ server will not be killed.
+ \item When ducc.database.autostart = false, the database will not be killed.
+ \end{itemize}
+
\subsubsection{\em{Usage: }}
\begin{description}