georgringer / t3monitoring

Monitoring service of TYPO3 extensions
GNU General Public License v2.0
46 stars 36 forks source link

[FEATURE] Show scheduler tasks of clients #232

Open cehret opened 2 days ago

cehret commented 2 days ago

Hello,

I think that this would be a great feature which - as far I can see - @hoermannklaus built for a former Version of this extension. I guess that the development of this feature stopped? Is there any reason?

I could invest some time in implementing this in the actual version of t3monitoring?

Greetings

Christian

hoermannklaus commented 2 days ago

Hi @cehret. I stopped the development of this feature, because there were adaptions necessary to the server as well as the client extension. And it was very annoying to always use my fork version of the client extension for all our projects, as the feature was never accepted into the main branch.

Still we were interested in monitoring the status of the scheduled tasks of a TYPO3 project. You would not know if the scheduled tasks are executed, if there was a problem or whatsoever regarding tasks. Thats why we developed another extension called: worlddirect/healthcheck.

This extension checks multiple probes and then returns a overall health status. Checking the scheduled tasks is a probe which gets shipped with the extension. But you could also easily develop your own probes. The healthcheck page then gets monitored by a 3rd party solution which the company I work for uses to check if everything is ok.

[!NOTE] The healthcheck is per project, and there is no "server" version, which again lists the status of all attached healthchecks!

Therefore we do not have a need for checking scheduled tasks in the t3monitoring client and server extension anymore.

Maybe you want to take a look at worlddirect/healthcheck and tell me what you think. There is also some documentation I wrote. If it is not enough, or does not make sense, let me know. I will try to make it better. 😉

cehret commented 2 days ago

@hoermannklaus Thank you for your comment and the link to healthcheck. This one looks good, too, but you need another software to display the results, send warning mails,... as far as I understood?

@georgringer what about building in the scheduler monitor into your extension? If I would update the code of Klaus is there any chance to add it into the master branch? Your do your extension has any hooks or something else to extend with another extension?

hoermannklaus commented 1 day ago

@cehret Yes, you are right. It requires another alarming system which monitors the healthcheck result and sends notifications. If you need anything regarding the code which I wrote for adding the scheduler stuff just contact me.

cehret commented 13 hours ago

@hoermannklaus thank you - I'd like to implement the scheduler stuff into t3monitoring the next weeks. Would be great if you could pass the code to me! I think your code for t3monitoring is in git but not for t3monitoring_client ?

@georgringer do you think we could implement this feature in t3monitoring or do I need to fork your extension?

hoermannklaus commented 12 hours ago

@cehret My fork with the code I adapted is located here: https://github.com/hoermannklaus/t3monitoring/tree/feature-tasks. Here is a link to the comparing changes for my fork: https://github.com/georgringer/t3monitoring/compare/master...hoermannklaus:t3monitoring:feature-tasks. Hope it is not too chaotic and makes sense to you.

When I think of it, I did actually not adapt the t3monitoring_client extension. I used a different technique. I added a custom "Provider" in the custom "Site" Extension for my project like so:

$GLOBALS['TYPO3_CONF_VARS']['EXT']['t3monitoring_client']['provider'][] = StatusReportProvider::class;

The provider itself was supplied by the projects custom "Site" Extension. The code above also was located in my "Site" extension.

This way it was not necessary to clone the t3monitoring_client Extension and always install my fork instead of the original one.

After some digging I also found the code for the ScheduledTaskProvider class. See here:

<?php

namespace  WorldDirect\BigCore\Provider;

use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Scheduler\Task\AbstractTask;
use TYPO3\CMS\Core\Database\ConnectionPool;
use T3Monitor\T3monitoringClient\Provider\DataProviderInterface;

/**
 * Class ScheduledTaskProvider
 *
 */
class ScheduledTaskProvider implements DataProviderInterface
{
    /**
     * Reads the scheduled tasks from the database and adds them to the data.
     *
     * @param array $data Client data
     *
     * @return array Client data with tasks
     */
    public function get(array $data): array
    {
        $qb = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_scheduler_task');
        $statement = $qb
            ->select('uid', 'description', 'nextexecution', 'lastexecution_time', 'lastexecution_failure', 'lastexecution_context', 'serialized_task_object')
            ->from('tx_scheduler_task')
            ->where(
                $qb->expr()->eq('disable', $qb->createNamedParameter(0, \PDO::PARAM_INT)),
                $qb->expr()->eq('deleted', $qb->createNamedParameter(0, \PDO::PARAM_INT))
            )
            ->execute();
        while ($row = $statement->fetch()) {
            $data['tasks'][] = $this->unserializeTask($row);
        }
        return $data;
    }

    /**
     * Unserialize a serialized task object. Fill some of the objects attributes
     * into the $task array and return it.
     *
     * @param array<string> $row The task row
     *
     * @return array<string> The task array
     */
    private function unserializeTask($row)
    {
        $task = unserialize($row['serialized_task_object']);
        $class = get_class($task);
        if ($class === \__PHP_Incomplete_Class::class && preg_match('/^O:[0-9]+:"(?P<classname>.+?)"/', $row['serialized_task_object'], $matches) === 1) {
            $class = $matches['classname'];
        }
        unset($row['serialized_task_object']);
        $row['class'] = $class;
        $row['interval'] = $task->getExecution()->getInterval();
        $row['cronCmd'] = $task->getExecution()->getCronCmd();
        $row['multiple'] = intval($task->getExecution()->getMultiple());

        if ($row['lastexecution_failure'] == null) {
            $row['lastexecution_failure'] = '';
        }

        if (!empty($row['interval']) || !empty($row['cronCmd'])) {
            $row['type'] = AbstractTask::TYPE_RECURRING;
            $row['frequency'] = $row['interval'] ?: $row['cronCmd'];
        } else {
            $row['type'] = AbstractTask::TYPE_SINGLE;
            $row['frequency'] = '';
        }
        unset($row['cronCmd'], $row['interval']);

        if ($row['nextexecution'] < $GLOBALS['EXEC_TIME']) {
            $row['late'] = 1;
        } else {
            $row['late'] = 0;
        }

        return $row;
    }
}

The code is quite old, so not sure about the usage of old or deprecated API methods.

If you have any questions or need anything please contact me.