Skip to content

[FEATURE] New operation - HasStuckSchedulerTask #35

Description

@wu-psvneo

As the title says. This is about a new operation for detecting a stuck scheduler task.

We recently had a customer where a scheduler task wouldn't stop running. This operation could help you detect such tasks.

I created the operation class myself to test it. @svewap , if you think this operation adds value to your extension, I would be happy to contribute to your project.

You can define the max runnign hours via parameter or use the default of 6 hours.

<?php

namespace WapplerSystems\ZabbixClient\Operation;

/**
 * This file is part of the "zabbix_client" Extension for TYPO3 CMS.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 */

use DateTime;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver\Exception;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Database\ConnectionPool;
use WapplerSystems\ZabbixClient\OperationResult;

class HasStuckSchedulerTask implements IOperation, SingletonInterface
{
    const MAX_RUNNING_HOURS = 6;

    /**
     * @param array $parameter
     * @return OperationResult
     *
     * @throws Exception|DBALException
     */
    public function execute($parameter = [])
    {
        $maxRunningHours = intval(isset($parameter['maxRunningHours']) ? $parameter['maxRunningHours'] : 0);
        // Make sure we do not use a number smaller than 1 here.
        if($maxRunningHours < 1) {
            $maxRunningHours = self::MAX_RUNNING_HOURS;
        }

        $schedulerRecords = $this->fetchSchedulerTasks();
        if (0 === count($schedulerRecords)) {
            // No tasks found.
            return new OperationResult(true, false);
        }

        foreach ($schedulerRecords as $schedulerRecord) {
            // Check if the task is running.
            $isRunning = !empty($schedulerRecord['serialized_executions']);
            if (!$isRunning) {
                continue;
            }
            // Validate for required column value (lastexecution_time).
            if (empty($schedulerRecord['lastexecution_time'])) {
                continue;
            }

            // Compare lastexecution_time with current time.
            $currentDateTime = new DateTime();
            $lastExecutedDateTime = (new DateTime())->setTimestamp((int)$schedulerRecord['lastexecution_time']);
            $runningHours = intval($currentDateTime->diff($lastExecutedDateTime)->format('%h'));
            $runningHours += intval($currentDateTime->diff($lastExecutedDateTime)->days) * 24;

            if ($runningHours >= $maxRunningHours) {
                return new OperationResult(true, true);
            }
        }

        // No task is running.
        return new OperationResult(true, false);
    }

    /**
     * @return array
     *
     * @throws Exception|DBALException
     */
    private function fetchSchedulerTasks()
    {
        /** @var ConnectionPool $connectionPool */
        $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
        $queryBuilder = $connectionPool->getQueryBuilderForTable('tx_scheduler_task');
        $queryBuilder
            ->select('uid', 'serialized_executions', 'lastexecution_time')
            ->from('tx_scheduler_task')
            ->where(
                $queryBuilder->expr()->eq('disable', $queryBuilder->createNamedParameter(0, Connection::PARAM_INT))
            );

        if (version_compare(TYPO3_version, '9.0.0', '>=')) {
            $queryBuilder->andWhere(
                $queryBuilder->expr()->eq('deleted', $queryBuilder->createNamedParameter(0, Connection::PARAM_INT))
            );
        }

        return $queryBuilder->execute()->fetchAllAssociative();
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions