使用WP队列将REST API数据复制到文件

最近来自Delicious Brains的Matt Shaw 发表了一篇关于他们创建的新图书馆的帖子,以帮助他们的一个产品。这个库WP_Queue为WordPress提供了类似Laravel的作业管理系统。作业队列是一个允许您安排将来运行的作业的系统。我们倾向于使用工作有两个原因。首先,我们可能需要等待一段时间,就像我们想要在一周内安排后续电子邮件一样。另一个原因是表现。也许我们需要做一些计算上昂贵的事情并且不希望用户等待。

一个工作经理给我们一个调度系统 – 一些存储工作直到他们需要运行的方式 – 一个工作运行员 – 一些用于运行工作的工具。WordPress的wp_cron有点适合这种描述。但是,通过使用WP_Queue,我发现它更符合我的需求。

WP_Queue

WP_Queue包看起来很适合一些reaons。首先,是作业是从运行者和调度员中抽象出来的。我可以编写一个工作类并将其作为单元进行单独测试。其次,作业调度程序是抽象的。默认情况下,作业记录在WordPress数据库中,然后在需要时,使用wp_cron进行调度。但我也可以使用开发驱动程序使它们同步,并且正在进行Redis驱动程序。所以让我们开始吧。

建立

WP_Queue库是一个composer包。首先,在您的插件中安装该软件包:

1
composer require a5hleyrich/wp-queue

您需要为调度程序添加数据库表。该软件包的自述文件包含说明。将其添加到插件的激活挂钩或添加自己的表的位置。

创造机会

如果你曾经使用过Laravel的作业队列,那么对\ WP_Queue \ Job类的结构就会很熟悉。你的工作类必须有一个handle()方法。在运行作业时调用该方法。你可能也会有一个__construct()方法。

理解这些类的关键概念是,在调度作业时将类的属性序列化到数据库,并在运行时用于实例化类。

例如,假设您希望创建一个作业,以便在保存帖子时运行。在__construct()方法中,您将传递帖子ID并使用该参数来设置属性。当handle方法运行时,将使用post ID设置该属性。在handle方法中,您可以使用该属性(随作业保存的已保存的帖子ID)从数据库中获取保存的帖子。这是看起来像:

1
2
3
4
5
6
7
8
9
10
11
12
class PostSaveJob extends \WP_Queue\Job
{
protected $postId;
public function __construct($postId)
{
$this->postId = $postId;
}
public function handle()
{
$post = get_post($this->postId);
}
}

保存时将帖子的JSON复制到文件

到目前为止我们所做的是从数据库中获取帖子的工作。这很酷,我们可以启动一个方法,安排这个工作在每次保存帖子时运行,并使这个工作获得保存的帖子的REST API响应并将其写入JSON文件。让我们向后完成该列表。

什么是订单?最后一个要求将是一个类,我可以单独测试,如果它有效,那么我可以设置方法并挂钩到save_post操作,我将知道该工作是有效的。如果反过来做,我将不知道我的问题是运行器还是队列。那是不科学的。

在使用不同的任务使用Torque之前保存帖子之后,我写了类似的关于运行作业的appraoch。

将帖子的JSON写入文件

让我们继续努力工作。我们拥有获得帖子所需的一切。我们需要获取WordPress REST API为帖子创建的响应对象,将其序列化为json并将该JSON写入文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class PostSaveJob extends \WP_Queue\Job
{
protected $postId;
public function __construct($postId)
{
$this->postId = $postId;
}
public function handle() {
$post = get_post( $this->postId );
if( ! in_array( get_post_type($post), [ 'post', 'page' ]) ){
return;
}
$controller = new \WP_REST_Posts_Controller( 'post' );
$route = 'wp/v2/posts/' . $this->postId;
$request = new \WP_REST_Request('GET', $route);
$request->set_param( 'id', $this->postId );
$response = $controller->get_item($request );
$name = sprintf( '%s/posts/%s.json', __DIR__, $post->post_name );
file_put_contents( $name, json_encode( $response ) );
return $name;
}
}

这是完整的工作。使用WordPress REST API的post控件来创建WP_REST_Response,并使用json_encode()将其作为字符串并将其保存到以post slug命名的文件中。

您存储文件的位置以及您调用的内容取决于您的需求。

现在,我们可以实例化这个类来测试它是否有效。我们可以用这样的方式直接运行它,其中$postId是已发布帖子的ID:

1
$fileName =(new \ calderawp \ WordPressPlugin \ Jobs \ PostSaveJob($postId)) - > handle();

然后,您应该在为写入文件设置的路径中看到一个带有帖子的JSON表示的文件。我们还可以为它编写集成测试:

1
2
3
4
5
6
7
8
class PostSaveJobTest extends TestCase {
public function testSaves(){
$postName ='foo';
$postId = wp_insert_post(['post_content'=>'fff''post_type'=>'post''post_status'=>'publish''post_name'=> $postName]);
$fileName =(new \ calderawp \ WordPressPlugin \ Jobs \ PostSaveJob($postId)) - > handle();
$this-> assertTrue(file_exists($ fileName));
}
}

调度帖子更新时要运行的作业

现在我们知道如果计划运行我们的工作会有效,我们需要安排它运行,只要保存帖子。保存帖子时会触发save_post操作,因此我们可以使用它。在回调函数中,我们将实例化作业类并将其传递给wp_queue() -> push()。

1
2
3
add_action('save_post'function($postId){
wp_queue() - > push(new PostSaveJob($postId));
});

这足以让它尽快安排运行。

延迟执行作业

push()方法的第二个参数是运行作业的延迟时间。最后一个代码示例没有使用该参数。一旦队列到达,作业就会运行。如果我们想将它延迟5分钟,可以通过设置600 – 5分钟 – 作为第二个参数。

1
2
3
add_action('save_post'function($postId){
wp_queue() - > push(new PostSaveJob($postId)600);
});

设置Job Runner

最后一步:我们需要设置队列才能运行。我们可以使用wp_cron运行队列:

1
2
3
add_action('plugins_loaded'function(){
wp_queue() -> wp_cron();
});

当您进行本地开发时,最好使用“sync”驱动程序而不是数据库驱动程序,以便作业同步运行。这使测试更容易。

1
2
3
add_filter('wp_queue_default_connection'function(){
return('sync');
});

不使用WP-CRON怎么做

我不打算列举wp_cron的许多缺点。但是,WP_Queue的真正酷点是我可以设置自己的系统来运行它。为了获得最佳性能,我不想依赖WordPress来触发wp_cron,我不想在其队列中添加更多“cron”作业。相反,我宁愿添加一个REST API端点并使用外部cron作业ping它,例如使用setCronJob.com运行一次。

我们可以使用函数wp_queue()访问队列。返回一个Queue对象,该对象具有一个名为worker()的公共方法。这将返回一个带有process()方法的Worker对象,如果可以处理任何作业,它将运行该作业。我们可以使用while循环来运行作业,直到进程返回false,并使用递增整数来阻止循环运行太多请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function workQueue($jobs = 10$attemptsPerJob = 3){
//获取正确配置的队列
$queue = wp_queue();
//获取队列的worker
$worker = $queue-> worker($attemptsPerJob);
//循环遍历队列中的作业,直到我们完成$ jobs中传递的数字
//或者没有剩下的工作要运行
$totalJobs = 0;
while($ worker-> process()&& $jobs <= $totalJobs){ $ totalJobs ++; } //处理队列和 return rest_ensure_response(['totalJobs' => $totalJobs]);
}
add_action('rest_api_init'function(){
register_rest_route('hi-roy''queue / run'[
'methods'=> ['POST''GET']
'callback'=>'workQueue'
]);
});

在这个例子中,我将它连接到REST API路由,这将允许外部cron服务触发队列。您管理服务器,使用真正的cron或只能从服务器/容器内部运行的命令来触发该功能是最安全的。如果那是不可能的,请在密钥身份验证检查或其它身份验证下实现。

说点什么

500