caseyamcl/tasktracker

一个用于跟踪长时间运行的任务进度和统计信息的PHP库

2.2.4 2019-04-11 19:01 UTC

This package is auto-updated.

Last update: 2024-09-23 03:04:41 UTC


README

一个用于在PHP中跟踪长时间运行任务的库(当简单的进度条不够用时)

Latest Version Software License Build Status Scrutinizer Code Quality

快速浏览:

  • 在长时间运行的任务期间报告内存使用情况和多个进度统计信息
  • 适用于执行大量小型作业的长时间运行过程
  • 使用 Symfony Event-Dispatcher Component 的事件驱动架构
  • 提供用于报告任务进度的内置实用工具

例如,您可能希望在任务执行期间在控制台上显示进度条,同时将系统状态的周期性快照发送到Monolog。使用单个Tracker对象,您可以同时实现这两个目标

use TaskTracker\Tracker,
    TaskTracker\Tick;
use TaskTracker\Subscriber\SymfonyConsoleProgress,
    TaskTracker\Subscriber\Psr3Logger;
use Symfony\Console\Output\ConsoleOutput;
use Monolog\Logger as MonologLogger;


// Setup subscribers
$subscribers = [
    new SymfonyConsoleProgress(new ConsoleOutput()),
    new Psr3Logger(new MonologLogger())
];

// Setup a tracker for a job with 100 items
$tracker = Tracker::build(100, $subscribers);

$tracker->start("Let's go");
for ($i = 0; $i < 100; $i++) {
    // Do some work of some sort...
    $tracker->tick();
}
$tracker->finish("All done");

安装

通过Composer安装

composer require caseyamcl/tasktracker:~2.0

手动安装

  1. http://github.com/caseyamcl/tasktracker下载源码。
  2. 使用PSR-4兼容的自动加载器将src/TaskTracker文件夹包含到您的代码中。

使用方法

要跟踪任务,创建Tracker类的实例

use TaskTracker\Tracker;

// Instantiate a tracker to track 100 items
$tracker = new Tracker(100);

如果您正在处理未知数量的项目,可以省略项目数量

$tracker = new Tracker();

Tracker类会创建自己的EventDispatcher,但您可以可选地注入自己的实例

$dispatcher = new \Symfony\Component\EventDispatcher\EventDispatcher();

$tracker = new Tracker(100, $dispatcher);
// ..or..
$tracker = new Tracker(Tracker::UNKNOWN, $dispatcher);

要开始跟踪,只需调用Tracker::start()方法

// Start the tracker
$tracker->start('optional starting message');

对于您处理的每个元素,调用Tracker::tick()方法,直到完成

// Tick
$tracker->tick();

有三种类型的Tick:成功(默认)、失败跳过

use Tracker\Tick;

$tracker->tick(Tick::SUCCESS);
$tracker->tick(Tick::FAIL);
$tracker->tick(Tick::SKIP);

您还可以提供可选的消息

$tracker->tick(Tick::SUCCESS, 'Things are going well.');
$tracker->tick(Tick::FAIL,    'Crud.  Something went wrong');
$tracker->tick(Tick::SKIP,    'Skipping this record for whatever reason');

您可以将自定义数据作为数组添加到Tick中

$tracker->tick(Tick::SUCCESS, 'Things are going well.', ['foo' => 'bar', 'baz' => 'biz]);

并且,您可以一次递增多个项目

// Increment by 5 items
$tracker->tick(Tick::SUCCESS, '', [], 5);

// Three items failed
$tracker->tick(Tick::FAIL, 'Something went wrong', [], 3);

完成时,调用Tracker::finish()方法

$tracker->finish('Optional finish manage');

或者,如果在处理过程中出现问题,可以中止

$tracker->abort('Optional abort message');

类还包含一些辅助方法

// Have we started processing yet?
$tracker->isRunning();

// Get the last tick (instance of \Tracker\Tick class)
$tracker->getLastTick();

// Get the status of the process as an int (Tracker::NOT_STARTED, Tracker::RUNNING, Tracker::FINISHED, or Tracker::ABORTED)
$tracker->getStatus();

// Get the number of items processed thus far
$tracker->getNumProcessedItems();

// Get only the number of failed items (works with SUCCESS and SKIP too)
$tracker->getNumProcessedItems(Tick::FAIL);

// Get the time started (in microseconds)
$tracker->getStartTime();

您可以使用Tracker:run($iterator, $callback)方法获得更简洁的语法。
$iterator值必须是\Traversable的实例;数组不接受,但ArrayIterator对象将工作

$iterator = new \ArrayIterator(['a', 'b', 'c']);

// This code is the equivalent of...
$tracker->run($iterator, function(Tracker $tracker, $item) {
    // work on a single item
    $tracker->tick();
});

//...this code:
$tracker->start();
foreach ($iterator as $item) {
    // work on a single item
    $tracker->tick();
}
$tracker->finish();    

订阅者

没有事件订阅者来监听跟踪器tick事件,Tracker类本身并不很有用。此库附带了一些订阅者

  • TaskTracker\Subscriber\Psr3Logger - 将跟踪器事件记录到任何PSR-3 Logger
  • TaskTracker\Subscriber\SymfonyConsoleLog - 将跟踪器事件记录到Symfony控制台,每个事件占一行。
  • TaskTracker\Subscriber\SymfonyConsoleProgress - 将跟踪器事件记录到Symfony控制台进度条指示器。

您可以通过调用Tracker::addSubscriber()方法将事件订阅者添加到跟踪器

$tacker = new Tracker(100);
$tracker->addSubscriber(new SymfonyConsoleLog($output));

如果您提前知道将要使用的订阅者,可以使用Tracker::build()方法来方便操作

$subscribers = [new SymfonyConsoleLog($output), new SomeOtherSubscriber()];
$tracker = Tracker::build(100, $subscribers);

示例

例如,假设您正在创建一个Symfony控制台命令,并希望为某个任务显示进度条,同时记录事件

use TaskTracker\Tracker;
use TaskTracker\Tick;
use TaskTracker\Subscriber\SymfonyConsoleProgress;
use Symfony\Component\Console\Command\Command;

/**
 * My Symfony Command
 */
class MyCommand extends Command
{
    protected function configure()
    {
        $this->setName('example');
        $this->setDescription("Demonstrate TaskTracker");
    }
   
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $numItems = 10;
    
        // Build Task Tracker with Symfony Console Progress Bar subscriber
        $tracker = Tracker::build([new SymfonyConsoleProgress($output)], $numItems);
        
        // Add a Monolog Listener after Tracker construction
        $monolog = new \Monolog\Logger(/* some handlers */);
        $tracker->addSubscriber(new Psr3Logger($monolog));
        
        // You can also add Event Listeners directly
        $tracker->getDispatcher()->addListener(\Tracker\Events::TRACKER_TICK, function(\Tracker\Tick $tick) {
            // do something...
        });
        
        // Tracker::start() is technically optional; if not called, it will automatically
        // be called upon the first Tick
        $tracker->start("Let's go!");
        
        // The SymfonyConsoleProgress listener will output a progress bar while the logger will log events
        for ($i = 0; $i < 10; $i++) {
            $tracker->tick(\Tick::SUCCESS, "On item: " . $i);
            sleep(1);
        }
        
        // Tracker::start(), Tracker::tick(), Tracker::abort(), and Tracker::finish() all return
        // a \Tracker\Report object.
        $report = $tracker->finish('All done!');
        
        $output->writeln(sprintf("All Done!  <info>%s</info> items processed", $report->getNumTotalItems()));
    }
}

自定义订阅者

TaskTracker使用了Symfony EventDispatcher库,因此任何兼容Symfony的事件监听器都可以使用。

您可以监听以下四个事件

  • TaskTracker\Events::TRACKER_START
  • TaskTracker\Events::TRACKER_TICK
  • TaskTracker\Events::TRACKER_FINISH
  • TaskTracker\Events::TRACKER_ABORT

所有四个事件都会分发一个TaskTracker\Tick类的实例。您的订阅者/监听器应该接受该类的对象作为参数

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use TaskTracker\Tick;

/**
 * Listen for Tracker Events
 */
class MyEventSubscriber implements EventSubscriberInterface
{
     public static function getSubscribedEvents()
     {
         return [
             TaskTracker\Events::TRACKER_START  => 'handle',
             TaskTracker\Events::TRACKER_TICK   => 'handle',
             TaskTracker\Events::TRACKER_FINISH => 'handle',
         ];
     }
     
     public static function handle(Tick $tickEvent)
     {
         // See all of the information about the progress of that tick
         var_dump($tickEvent->getReport()->toArray());
     }
}

报告

每个Tracker事件都会发射一个携带过程快照和一些系统信息的\Tracker\Report对象,这些信息是在事件发生的时间点存在的。

$report = $tracker->tick();

$report->getTimeStarted();
$report->getTotalItemCount();
$report->getTick();
$report->getNumItemsProcessed();
$report->getTimeElapsed();
$report->getNumItemsSuccess();
$report->getNumItemsFail();
$report->getNumItemsSkip();
$report->getItemTime();
$report->getMaxItemTime();
$report->getMinItemTime();
$report->getAvgItemTime();
$report->getMemUsage();
$report->getMemPeakUsage();
$report->getMessage();
$report->getTimestamp();
$report->getStatus();
$report->getIncrementBy();
$report->getReport();
$report->getExtraInfo();

在您的订阅者中,您可以通过调用Tick::getReport()Tick对象中访问报告。