#!/bin/ksh

# Component: taskd
#
# Description:
#  Control script of component taskd
#

#--- INIT ------------------------------
#needs $HOME
. $HOME/etc/ctrl.main.shi

[ -f $HOME/etc/setenv.sh ] && . $HOME/etc/setenv.sh

[ -f $TASKD_PID ] && PID=`cat "$TASKD_PID" 2>&1`
[ "" = "$PID" ] && PID="$$.not"

#--- FUNC ------------------------------
do_shell_()
{
	if [ -f "$ETC/virthost.sh" ]; then
		. "$ETC/virthost.sh"
	fi
	[ -z "$JAVA_SERVER_PORT" ] && JAVA_SERVER_PORT=5555
	[ -z "$SHARED_TASKD_TASKID" ] && SHARED_TASKD_TASKID=1000
	[ -z "$SEMAPHORE_TASKD_TASKID" ] && SEMAPHORE_TASKD_TASKID=1000

	cat <<-EndOfInlineData
		TASKD_HOME=$HOME/component/taskd
		TASKD_PID=\$RUN/taskd.pid
		TASKD_CONF=\$CONF/taskd.cfg
		JAVA_SERVER_PORT=$JAVA_SERVER_PORT
		TASKD_GLOBALQUEUE=\$VAR/taskqueue
		TASKD_DATA=\$DATA/taskd
		SHARED_TASKD_TASKID=$SHARED_TASKD_TASKID
		SEMAPHORE_TASKD_TASKID=$SEMAPHORE_TASKD_TASKID	
		TASKQUEUETBL=TaskQueue

	EndOfInlineData

} #do_shell_()


do_crontab_()
{
	# Get times from crontabSchedule settings 
	[ -f "$CONF/crontabSchedule.shi" ] && . $CONF/crontabSchedule.shi
	
	# time to check if taskd directory files are too big
	[ -z "$CheckTaskdDirs" ] && CheckTaskdDirs="02 *"

	cat <<-EOI
		$CheckTaskdDirs * * * $TASKD_HOME/checkDirs.sh >/dev/null 2>&1
	EOI
}


#
# Creates default taskd config file
#
create_default_config_()
{
	cat <<-ENDOFDEFAULTBODY >> $TASKD_CONF
		DEFAULT_MAX_RETRY_NUM="60"
		DEFAULT_MAX_DELAY_SEC="7200"
		DEFAULT_FIRST_DELAY_SEC="120"
		DEFAULT_INCREASE_DELAY_SEC="600"
		DEFAULT_INCREASE_DELAY_STEP="5"
		OVERLOAD_TRUE="500000"
		OVERLOAD_FALSE="450000"
		OVERLOAD_MAILGROUP="Admin"
	ENDOFDEFAULTBODY
}


do_start_()
{
	if [ ! -f "$TASKD_CONF" ] ; then
		# taskd.cfg does not exist - new install

		# NEW INSTALL
		create_default_config_
	fi

	if [ ! -e "/proc/$PID" ]; then
		
		if [ -n "$(ps -C java h | grep Taskd | grep $JAVA_HOME)" ] ; then
			echo " WARNING: taskd is already running" >&2
			echo ps h | grep Taskd | grep $JAVA_HOME
			exit 1
		fi
	
		echo "start taskd"

		if [ "$1" = "debug" ] ; then
			cat <<-ENDTASKDOPTIONS > $RUN/taskd.options
				TASKD_OPTIONS="-Xrunjdwp:transport=dt_socket,address=8600,server=y,suspend=n"
			ENDTASKDOPTIONS
		elif [ "$1" = "nodebug" ] ; then
			[ -f "$RUN/taskd.options" ] && rm $RUN/taskd.options
		fi

		TASKD_OPTIONS=""
		[ -f "$RUN/taskd.options" ] && . $RUN/taskd.options

		CWD=`pwd`
		cd $TASKD_HOME
		
		CLASSPATH=":$CLASSPATH:$HOME/component"
		export CLASSPATH

		# Check if CONF/taskdjava.cfg exists and pick up TASKDJAVA_OPTS from this file
		# TASKDJAVA_OPTS is for passing extra options (eg. system properties) to taskd java
    	# if there is a TASKDJAVA_NICE in it, it will override earlier ones
		if [ -f "$CONF/taskdjava.cfg" ] ; then
		   . $CONF/taskdjava.cfg
		fi
		
		# if we don't have TASKDJAVA_MAXMEMORY coming from taskdjava.cfg, we set it to default 3GB
		if [ -z "$TASKDJAVA_MAXMEMORY" ] ; then
			TASKDJAVA_MAXMEMORY="3072m"
		fi
		
		$JAVA_HOME/bin/java $TASKD_OPTIONS -cp $TASKD_HOME/jar/taskd.jar:lib/jetty-all-9.2.10.v20150310.jar:lib/servlet-api-3.1.jar:$PROTOBUF_HOME/jar/protobuf-2.6.1.jar:$CLASSPATH:$CLASSES_HOME -Xmx$TASKDJAVA_MAXMEMORY -XX:+HeapDumpOnOutOfMemoryError -XX:+StartAttachListener $JAVA_OPTS $TASKDJAVA_OPTS $LOG4J_ARGS -Djava.locale.providers=COMPAT,CLDR -DTaskd=true -Dpacs.self.machine=local -Dpacs.self.host=taskd imagemed.taskd.Taskd >>$LOG/javataskd.log 2>&1 &
	
		thepid=$!
		 
		echo $thepid >$TASKD_PID
       		
		[ -n "$TASKDJAVA_NICE" ] && renice $TASKDJAVA_NICE $thepid >/dev/null
		
		[ -n "$TASKD_OPTIONS" ] && echo "Component taskd has been started in DEBUG mode on port 8600"

		cd $CWD
	else
		echo "--- Component taskd[$0 $$]: taskd is running"
	fi

} #do_start_()


#
# $1 might be soft:
#
do_stop_()
{
	>/tmp/taskd.kill.$PID

	if [ -f "$TASKD_PID" ] ; then
		
		taskdPid=`cat $TASKD_PID`
		while ps --no-heading -p $taskdPid >/dev/null ; do
			$TASKD_HOME/runjavacmd -c "kill" -p $JAVA_SERVER_PORT
			sleep 1
		done	
			
		rm $TASKD_PID
	fi
} #do_stop_()

do_status_()
{
	if [ ! -f $TASKD_PID ]; then
		echo "STOPPED"
		exit
	fi
  
	ps auxwww | grep task[d] | grep -q `cat $TASKD_PID`
	if [ $? != 0 ] ; then
		echo "ERROR"
		exit
	fi

    $TASKD_HOME/runjavacmd -c "ping2" -p $JAVA_SERVER_PORT
	if [ $? -ne 0 ] ; then
		echo "ERROR-LISTENER"
		exit
	fi

	echo "OK"

} #do_status_()

do_beforesubmit_()
{
  do_stop_

} #do_beforesubmit_()

do_aftersubmit_()
{ 
  do_start_

} #do_aftersubmit_()

do_emergency_()
{
  tempLogFile="$TMP/capture.$$.log.tmp"
  $ETC/rc capture >>$tempLogFile
  date "+%Y/%m/%d %H:%M:%S" >>$LOG/capture.log
  cat $tempLogFile >>$LOG/capture.log
  
# no, we don't want to stop/start automatically when in ERROR state, it causes more harm than good  
#  do_stop_
#  sleep 10
#  do_start_

} #do_emergency_()


#
# List files/tables to be backed up grouped by categories
#
# output lines should be in '<category> <type> <names>' format
#
do_listbackup_()
{
	cat <<-EOFLISTBACKUP
		config.system FILE ${CONF#$HOME/}/taskd.cfg ${CONF#$HOME/}/resources.cfg ${CONF#$HOME/}/deviceResources.cfg ${CONF#$HOME/}/priorities.cfg 
		data.taskd FILE ${TASKD_GLOBALQUEUE#$HOME/} 
	EOFLISTBACKUP
}



calcDiffAndPrint_()
{
	awk -vactDateTime="$1" -vsubstrahend="$2" -vtoWrite="$3" '
		BEGIN{
			diff=0;
			if (actDateTime>substrahend) {
				actDate=substr(actDateTime,1,8);
				subDate=substr(lsubstrahend,1,8);
				if (subDate<actDate) {
					actYear=substr(actDateTime,1,4);
					actMon=substr(actDateTime,5,2);
					actDay=substr(actDateTime,7,2);
					subYear=substr(substrahend,1,4);
					subMon=substr(substrahend,5,2);
					subDay=substr(substrahend,7,2);
					
					actDateDay=(actYear-2000)*365+(actMon-1)*30+actDay;
					subDateDay=(subYear-2000)*365+(subMon-1)*30+subDay;
					diff=86400*(actDateDay-subDateDay);
				}
				actHour=substr(actDateTime,9,2);
				actMin=substr(actDateTime,11,2);
				actSec=substr(actDateTime,13,2);
				subHour=substr(substrahend,9,2);
				subMin=substr(substrahend,11,2);
				subSec=substr(substrahend,13,2);
				
				actTimeSec=actHour*3600+actMin*60+actSec;
				subTimeSec=subHour*3600+subMin*60+subSec;
				diff=diff+actTimeSec-subTimeSec;
			}
			print toWrite"="diff;
		}'
}



do_monitor_()
{
#the name 'net_queue' is used for legacy reasons
	net_queue_critical_priority_bound="0200"

	[ -f $CONF/crucialStage.cfg ] && . $CONF/crucialStage.cfg
	[ -f $DRWARSON_CONFIG/crucialStage.cfg ] && . $DRWARSON_CONFIG/crucialStage.cfg

	echo -n "taskd_net_f_counter="
	$TOOLS_HOME/qst.sh -P failed 2>/dev/null

	echo -n "taskd_net_r_counter="
	$TOOLS_HOME/qst.sh -P retry 2>/dev/null

	echo -n "taskd_net_s_counter="
	$TOOLS_HOME/qst.sh -P scheduled 2>/dev/null


	echo -n "taskd_net_f_crit_counter="
	$TOOLS_HOME/qst.sh -P -u 200 failed 2>/dev/null

	echo -n "taskd_net_r_crit_counter="
	$TOOLS_HOME/qst.sh -P -u 200 retry 2>/dev/null

	echo -n "taskd_net_s_crit_counter="
	$TOOLS_HOME/qst.sh -P -u 200 scheduled 2>/dev/null


	oldestcritical=$(echo "select substr( min(TQTASKID), 1, 14) from TaskQueue where TQPRI<$net_queue_critical_priority_bound AND TQQUEUE='scheduled'" | $MYSQL_HOME/bin/mysql -N $DBNAME 2>/dev/null )
	if [ $? = 0 ] && [ $oldestcritical != "NULL" ] ; then 
		calcDiffAndPrint_ `date +"%Y%m%d%H%M%S"` "$oldestcritical" "taskd_net_s_largest_critical_lag"
	else
		# in case of MySQL problem we log 0 
		echo "taskd_net_s_largest_critical_lag=0"
	fi
		
	oldestnoncritical=$(echo "select substr( min(TQTASKID), 1, 14) from TaskQueue where TQQUEUE='scheduled'" | $MYSQL_HOME/bin/mysql -N $DBNAME 2>/dev/null )
	if [ $? = 0 ] && [ $oldestnoncritical != "NULL" ] ; then 
		calcDiffAndPrint_ `date +"%Y%m%d%H%M%S"` "$oldestnoncritical" "taskd_net_s_largest_noncritical_lag"
	else
		# in case of MySQL problem we log 0 
		echo "taskd_net_s_largest_noncritical_lag=0"
	fi
}




#
# Kills a process, and sends a kill -9 if the process does not terminate on regular kill
#
# $1 - pid of the process to kill
#
kill_() {
	local pid=$1

	[ -z "$1" ] && return

	if ps --pid "$pid" >/dev/null ; then
		kill $pid >/dev/null 2>/dev/null
		if ps --pid "$pid" >/dev/null ; then
			kill -9 $pid 2>/dev/null
		fi
	fi
}


#
# Executes a command and kills after a given timeout
#
# $1 - timeout seconds
# $@ - command and arguments to execute
#
timeout_() {
	local to
	local pid
	local waiter
	local exitcode

	to=$1
	shift

	# start the command in background
	( $@ 2>&1 ) & pid=$!


	# start a background process to kill command after timeout expired
	(sleep $to && kill_ $pid) & waiter=$!


	# wait for the command to complete
	wait $pid

	# exit code of the process - indicates whether it was killed or not
	exitcode=$?

	# kill the 'timeout killer' process if still runs
	kill_ $waiter

	return $exitcode
}


do_capture_()
{
	echo "Running tasks:"
	$TASKD_HOME/runjavacmd -c "info"
	taskdPid=`cat $TASKD_PID`
	if [ -n "$taskdPid" ] ; then
	kill -QUIT $taskdPid
		timeout_ 10 $JAVA_HOME/bin/jstack $taskdPid 2>/dev/null 
		if [ $? -ne 0 ] ; then
			timeout_ 10 $JAVA_HOME/bin/jstack -F $taskdPid 2>/dev/null
			if [ $? -ne 0 ] ; then
				echo "Capturing Taskd threads failed"
			fi
		fi
	else 
		echo "No Taskd PID found" 
	fi
}

#--- MAIN ------------------------------

check_action_ $1
if [ 0 = $? ]; then
  do_$1_ $2

else
  echo "--- Component taskd [ctrl $$]: Bad command: $1" >&2
  exit 1

fi
