swoft2 教程系列-任务详解

基本功能介绍

引用官方的介绍

某些场景对主流程没有依赖,可以直接使用任务来实现类似这些功能。框架为开发者提供了 协程 和 异步 两种任务。切记无论是 协程任务 还是 异步任务,任务里面操作都 只支持协程,且只能使用框架封装的所有 IO 操作(数据库、缓存…)

协程任务投递任务的时候不会阻塞主进程相当于一次协程调用,一般用于需要等待任务结果返回的场景。
有些场景主流程并不关心的任务执行的结果,此时就可以使用异步任务。

本人的理解

任务把一系列常用操作进行封装,使用协程可以大大的提高系统的效率,本人推荐使用任务来处理一些频繁调用的操作,例如数据库读取,可以分装到携程任务里.这里我们只介绍3种任务携程任务,异步任务,定时任务.关于同步任务我们不做介绍,因为同步任务和携程任务只能2选择1,我们推荐使用携程任务,一些非携程任务需要执行的操作可以分装成RPC服务,通过调用服务的方式来解决.

功能的相关配置选项

'httpServer' => [
 'class' => HttpServer::class,
 'port' => 18306,
 'listener' => [
 'rpc' => bean('rpcServer')
 ],
 'process' => [
//            'monitor' => bean(MonitorProcess::class)
 'crontab' => bean(CrontabProcess::class) //开启定时任务
 //'log' => bean(\App\Process\LogProcess::class)
 ],
 'on' => [
 SwooleEvent::TASK   => bean(SyncTaskListener::class), // 开启异步任务
 SwooleEvent::TASK   => bean(TaskListener::class), //开启携程任务监听
 SwooleEvent::FINISH => bean(FinishListener::class) //开启任务监听的回调
 ],
 /* @see HttpServer::$setting */
 'setting' => [
 'task_worker_num' => 12,
 'task_enable_coroutine' => true, //这个一定要设置为true
 'worker_num' => 6
 ]
 ],

task_enable_coroutine 必须为 true

task 事件和 finish 事件必须配置,且为 TaskListener::class 和 FinishListener::class

异步任务必须加入SyncTaskListener::class

任务配置与启用,在 Http Server / Rpc Server / Websocket Server 都完全一样.我们这里只列出了 Http Server 的配置

简单的示例

使用任务前,必须定义任务,定义任务很简单。如下定一个任务:

注意任务一般放到 app/task 目录下,官方已经帮我们创建了简单的实例,所以在官方原有的示例上修改即可

官方给出了示例

文件介绍

CronTask 为定时任务

扫描二维码关注公众号,回复: 10118156 查看本文章

SyncTask 为异步任务

TestTask 为携程任务

FinishListener 如果异步任务需要监听返回值,则在这里处理

namespace App\Task\Task;

use Swoft\Task\Annotation\Mapping\Task;
use Swoft\Task\Annotation\Mapping\TaskMapping;

/**
 * Class TestTask
 *
 * @since 2.0
 *
 * @Task(name="testTask") 
 */
class TestTask
{
 /**
     * @TaskMapping(name="list")
     *
     * @param int    $id
     * @param string $default
     *
     * @return array
     */
 public function getList(int $id, string $default = 'def'): array
 {
        $rs = context()->getRequest();
        echo $rs->getName() //输出任务名称
 return [
 'list' => [1, 3, 3],
 'id' => $id,
 'default' => $default
 ];
 }
}

代码分析

需要使用的注解

@Task 注解

标记类是一个任务 这个注解是必须的,且必须定义成类注解,推荐传入name,给任务定义名称.

@TaskMapping 注解

标记方法是一个任务映射,定义任务映射的名称,必须定义,如果方法没有使用 @TaskMapping 注解,不会解析成任务。同样推荐传入name,给任务方法名称.

写代码很多时候不需要问为什么,对于学习一个框架而言,第一步是去照着例子使用它,所以尽量的跟着官方代码来修改,多尝试.

任务触发

携程任务触发

投递单个任务

 Task::co(string $name, string $method, array $params = [], float $timeout = 3, array $ext = [])

 //调用例子
 $data = Task::co('testTask', 'list', [11,"wike_async"]);

参数详解

name 投递任务任务名称

我们上面定义的为 testTask (Task注解的值)

method 投递任务的方法名称

我们上面定义的为 list (TaskMapping注解的值)

params 任务传递的参数即是任务方法的参数,数组格式传递

例如 [10,”覆盖默认值”]

timeout 超时时间,默认 3s 超时

一般不需要修改,如果需要配置根据你的业务场景修改,如果需要任务没有超时限制,则使用异步任务

ext 任务扩展信息,会传递给任务进程里面

这个参数用的不多,一般场景不需要使用

一次性投递多个任务

Task::cos(array $tasks, float $timeout = 3, array $ext = [])

调用例子

输出

携程任务上下文

上下文获取方式

$rs= context()->getRequest()

常用方法

$rs->getServer();

getServer 获取任务 Server 信息

$rs->getTaskId();

获取任务 ID,对应 Swoole 任务 ID

$rs->getSrcWorkerId();

获取任务来自的 workerId

$rs->getData();

获取投递任务的原始是数据

$rs->getName();

获取任务名称

$rs->getMethod();

获取任务方法

$rs->getParams();

获取任务参数

$rs->getExt();

获取任务扩展信息

$rs->getType();

获取任务类型

$rs->getTaskUniqid();

获取任务全局唯一ID

异步任务投递

异步任务的定义和携程任务的定义流程是一样的,只是方法中,携程任务有上下文而异步任务没有.
Task::async(string $name, string $method, array $params = [], array $ext = [], int $dstWorkerId = -1, callable $fallback = null)
异步任务投递,返回一个全局唯一的任务ID

调用例子

$data = Task::async('sync', 'test', [12,"wike_async"]);

参数详解

name 投递任务任务名称

method 投递任务的方法名称

params 任务传递的参数即是任务方法的参数,数组格式传递

ext 任务扩展信息,会传递给任务进程里面

dstWorkerId 投递的进程 workerId,默认底层按需选择进程 workerId

fallback 失败的回调函数

异步任务我们一般是不关心返回结果的,但有些场景下我们需要监听返回结果.下面我们介绍下个人的处理方式

在异步任务的返回值中返回一个数组

代码如下

namespace App\Task\Task;

use Swoft\Task\Annotation\Mapping\Task;
use Swoft\Task\Annotation\Mapping\TaskMapping;

/**
 * Class SyncTask
 *
 * @since 2.0
 *
 * @Task(name="sync")
 */
class SyncTask
{
 /**
     * @TaskMapping()
     *
     * @param string $name
     *
     * @return string
     */
 public function test(string $name): array
 { 
 return ['sync-test-' . $name,$taskname];
 }
}

修改FinishListener文件

代码如下

namespace App\Task\Listener;

use function context;
use Swoft\Event\Annotation\Mapping\Listener;
use Swoft\Event\EventHandlerInterface;
use Swoft\Event\EventInterface;
use Swoft\Log\Helper\CLog;
use Swoft\Task\TaskEvent;

/**
 * Class FinishListener
 *
 * @since 2.0
 *
 * @Listener(event=TaskEvent::FINISH)
 */
class FinishListener implements EventHandlerInterface
{
 /**
     * @param EventInterface $event
     */
 public function handle(EventInterface $event): void
 {
 // CLog::info(context()->getTaskUniqid());

        $taskData = context()->getTaskData();
        $data=json_decode($taskData,true);

        $returndata=$data['result'][0];
        $taskname=$data['result'][1];
        echo $returndata."\n";
        echo $taskname."\n";
 if($taskname=="a"){
 //执行异步a任务处逻辑
 }
 if($taskname=="b"){

 //执行异步b任务处理逻辑
 }

 CLog::info($taskData);
 }
}
你可以根据自己的需要修改代码,只需要逻辑对应上就可以了,返回值不一定必须2个参数,可以3个或多个,只要监听函数对应的修改即可

定时任务

在某些情况下需要定时的去执行某些任务,通常我们会使用 Linux 系统自带的 Crontab 去定时的执行我们编写好的脚本,但是这样及其不方便,首先 Linux 系统默认的 Crontab 最小单位只能支持到分钟,无法支持秒级任务,其次,如果我们重新编写脚本,则不能很方便友好的复用框架内的资源,如 Mysql 连接资源,框架中的各种类库。针对以上问题,框架为我们内置了一个 Crontab 组件,可以支持秒级任务。

简单示例

namespace App\Task\Crontab;

use Swoft\Crontab\Annotaion\Mapping\Cron;
use Swoft\Crontab\Annotaion\Mapping\Scheduled;
use Swoft\Log\Helper\CLog;

/**
 * Class CronTask
 *
 * @since 2.0
 *
 * @Scheduled(name="wikecrontab")
 */
class CronTask
{
 /**
     * @Cron("* * * * * *")
     *
     */
 public function secondTask(): void
 {
 CLog::info('second task run: %s ', date('Y-m-d H:i:s'));
 }

 /**
     * @Cron("0 * * * * *")
     */
 public function minuteTask(): void
 {
 CLog::info('minute task run: %s ', date('Y-m-d H:i:s'));
 }
}

代码分析

需要使用的注解

@Scheduled()

用于声明定时任务,如果是声明定时任务类,则必须使用此注解

使用示例:@Scheduled()、@Scheduled(“taskName”)、@Scheduled(name=”taskName”) 建议设置,在手动触发时有用.

@Cron()

声明需要运行的方法,如果没有使用此注解,则该方法不会被运行。

使用示例: @Cron(“ “)、@Cron(value=” “),表达式可简写,例如一个每秒都要执行的任务则可定义为 @Cron(“*”)

Cron格式说明

* * * * * *
- - - - - -
| | | | | |
| | | | | +----- day of week (0 - 6) (Sunday=0)
| | | | +----- month (1 - 12)
| | | +------- day of month (1 - 31)
| | +--------- hour (0 - 23)
| +----------- min (0 - 59)
+------------- sec (0-59)

示例:

* * * * * * 表示每秒执行一次。

0 * * * * * 表示每分钟的第0秒执行一次,即每分钟执行一次。

0 0 * * * * 表示每小时的0分0秒执行一次,即每小时执行一次。

0/10 * * * * * 表示每分钟的第0秒开始每10秒执行一次。

10-20 * * * * * 表示每分钟的第10-20秒执行一次。

10,20,30 * * * * * 表示每分钟的第10,20,30秒各执行一次。 

手动执行

除了定时执行我们设置好的任务外,我们还可以在业务代码中直接手动执行我们的定时任务,方法如下。

 $crontab = BeanFactory::getBean("crontab");

 $crontab->execute("wikecrontab", "secondTask");

控制台输出

发布了543 篇原创文章 · 获赞 32 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/weixin_36691991/article/details/105045320