【问题标题】:WordPress post_exists returning wrong value (timeout issue?)WordPress post_exists 返回错误值(超时问题?)
【发布时间】:2018-09-22 03:45:41
【问题描述】:

我有一个 WordPress 网站的客户,他不太懂技术,不想自己更新网站。网站上有一个页面将她自己的内容从她雇主的博客中联合起来。她雇主的网站没有 RSS 提要,但我可以使用 PHP Simple HTML DOM Parser 设置一个简单的脚本来抓取要联合的内容,并为她雇主网站上的每个新条目创建一个新的 WordPress 帖子。我每周执行一次 cron 任务,这与她为雇主网站编写新内容的频率一样。

我遇到的问题是,当我的 cron 脚本执行时间超过 30 秒时,WordPress 的 post_exists 函数无法找到我搜索的第一个条目,并创建了一个重复的帖子。

以下是 cron 脚本的代码。为了我客户的隐私,我将所有可识别信息替换为[[placeholder]]

<?php
require( 'wp-load.php' );
if ( !function_exists( 'post_exists' ) ) {
    require_once( ABSPATH . 'wp-admin/includes/post.php' );
}
require( 'simple_html_dom.php' );

update_bac();

function update_bac()
{
    // log each cron execution for easier troubleshooting in the event of issues
    $logfile = 'bac_cron.log';
    file_put_contents( $logfile, date( "Y-m-d H:i:s" ) . "  \n", FILE_APPEND );
    file_put_contents( $logfile, date( "Y-m-d H:i:s" ) . "  Cron executed\n", FILE_APPEND );

    // Set a long time limit to avoid cron timeouts
    $time_limit_success = (set_time_limit( 900 )) ? 'TRUE' : 'FALSE';
    file_put_contents( $logfile, date( "Y-m-d H:i:s" ) . "  set_time_limit successful? {$time_limit_success} \n", FILE_APPEND );

这里删除的是执行实际抓取的代码。它工作,并构造了一个数组$entries_to_post,其中每个项目都是一个帖子数据数组,带有一个帖子标题('name'),一个“Y-m-d H:i:s”格式的发布日期('date'),雇主网站上帖子的链接 ('href') 和图片来源 ('img')。

    // create a WordPress post for each entry in the array that doesn't already exist in the database
    foreach( $entries_to_post as $postdata )
    {
        file_put_contents( $logfile, date( "Y-m-d H:i:s" ) . "  Looping entries_to_post, found {$postdata['name']}, {$postdata['date']} \n", FILE_APPEND );

        $matching_post_id = post_exists( $postdata['name'], '', $postdata['date'] );

根据 WordPress 的文档,post_exists 应在命中时返回帖子 ID,如果不存在此类帖子,则返回 0。第一个参数是帖子标题,第二个参数是帖子内容(所有帖子都有空内容,因为我对所有相关数据都使用了自定义字段),第三个参数是发布日期。

        if( $matching_post_id === 0 )
        {
            file_put_contents( $logfile, date( "Y-m-d H:i:s" ) . "  Match not found in database, adding new post... \n", FILE_APPEND );

            $postarr = [
                'post_author' => 0,
                'post_date' => $postdata['date'],
                'post_title' => $postdata['name'],
                'post_status' => 'publish',
                'post_type' => '[[custom-post-type]]'
            ];
            $post_id = wp_insert_post( $postarr, true );

            if( is_int( $post_id ) )
            {
                update_field( 'field_5741032e15daf', $postdata['href'], $post_id );
                update_field( 'field_5b93201831b5d', $postdata['img'], $post_id );

update_field 是高级自定义字段功能;创建帖子后,我在这里使用它来更新必要的自定义字段。

                file_put_contents( $logfile, date( "Y-m-d H:i:s" ) . "  Post created: " . $post_id . ", " . $postdata['name'] . ", " . $postdata['href'] . "\n", FILE_APPEND );
            }
            // wp_insert_post returns a WP_Error instead of a post ID if it fails
            else if( is_wp_error( $post_id ) )
            {
                file_put_contents( $logfile, date( "Y-m-d H:i:s" ) . "  Something went wrong!\n", FILE_APPEND );
                file_put_contents( $logfile, date( "Y-m-d H:i:s" ) . "  " . $post_id->get_error_message(), FILE_APPEND );
            }
        }
        else
        {
            file_put_contents( $logfile, date( "Y-m-d H:i:s" ) . "  Matching post found with ID {$matching_post_id} \n", FILE_APPEND );
        }
    }

    file_put_contents( $logfile, date( "Y-m-d H:i:s" ) . "  Reached end of array\n", FILE_APPEND );
}

如果 cron 执行时间少于 30 秒,则它按预期工作,如果没有新条目,则日志文件如下所示:

2018-09-21 17:36:03  
2018-09-21 17:36:03  Cron executed
2018-09-21 17:36:03  set_time_limit successful? TRUE 
2018-09-21 17:36:24  Looping entries_to_post, found [[post-title-1]], 2018-06-08 00:00:00 
2018-09-21 17:36:24  Matching post found with ID 516 
2018-09-21 17:36:24  Looping entries_to_post, found [[post-title-2]], 2018-07-12 00:00:00 
2018-09-21 17:36:24  Matching post found with ID 475 
2018-09-21 17:36:24  Looping entries_to_post, found [[post-title-3]], 2018-08-31 00:00:00 
2018-09-21 17:36:24  Matching post found with ID 476 
2018-09-21 17:36:24  Looping entries_to_post, found [[post-title-4]], 2018-08-17 00:00:00 
2018-09-21 17:36:24  Matching post found with ID 477 
2018-09-21 17:36:24  Looping entries_to_post, found [[post-title-5]], 2018-09-07 00:00:00 
2018-09-21 17:36:24  Matching post found with ID 478
...
2018-09-21 17:36:24  Reached end of array

如果执行时间超过 30 秒,则日志如下所示:

2018-09-21 16:53:27  
2018-09-21 16:53:27  Cron executed
2018-09-21 16:53:27  set_time_limit successful? TRUE 
2018-09-21 16:54:27  
2018-09-21 16:54:27  Cron executed
2018-09-21 16:54:27  set_time_limit successful? TRUE 
2018-09-21 16:55:01  Looping entries_to_post, found [[post-title-1]], 2018-06-08 00:00:00 
2018-09-21 16:55:01  Matching post found with ID 516 
2018-09-21 16:55:01  Looping entries_to_post, found [[post-title-2]], 2018-07-12 00:00:00 
2018-09-21 16:55:01  Matching post found with ID 475 
2018-09-21 16:55:01  Looping entries_to_post, found [[post-title-3]], 2018-08-31 00:00:00 
2018-09-21 16:55:01  Matching post found with ID 476 
2018-09-21 16:55:01  Looping entries_to_post, found [[post-title-4]], 2018-08-17 00:00:00 
2018-09-21 16:55:01  Matching post found with ID 477 
2018-09-21 16:55:01  Looping entries_to_post, found [[post-title-5]], 2018-09-07 00:00:00 
2018-09-21 16:55:01  Matching post found with ID 478
...
2018-09-21 16:55:01  Reached end of array
2018-09-21 16:55:02  Looping entries_to_post, found [[post-title-1]], 2018-06-08 00:00:00 
2018-09-21 16:55:02  Match not found in database, adding new post... 
2018-09-21 16:55:02  Post created: 526, [[post-title-1]], [[href]]
2018-09-21 16:55:02  Looping entries_to_post, found [[post-title-2]], 2018-07-12 00:00:00 
2018-09-21 16:55:02  Matching post found with ID 475 
2018-09-21 16:55:02  Looping entries_to_post, found [[post-title-3]], 2018-08-31 00:00:00 
2018-09-21 16:55:02  Matching post found with ID 476 
2018-09-21 16:55:02  Looping entries_to_post, found [[post-title-4]], 2018-08-17 00:00:00 
2018-09-21 16:55:02  Matching post found with ID 477 
2018-09-21 16:55:02  Looping entries_to_post, found [[post-title-5]], 2018-09-07 00:00:00 
2018-09-21 16:55:02  Matching post found with ID 478 
...
2018-09-21 16:55:02  Reached end of array

...s 只是一堆额外的循环迭代,总共大约 40 次——为简洁起见,我截断了日志。

如您所见,如果时间超过 30 秒,则 cron 会执行两次。第二次执行恰好在第一次执行后一分钟发生,但由于某种原因,它在第二次执行时立即循环遍历数组两次,并且在其中一个循环(有时是第一个循环,有时是第二个循环)中,第一项没有找到 post_exists 的数组,并创建了一个重复的帖子。

我尝试过的事情:

  • 我将 if( !post_exists(...) ) 更改为 if( post_exists(...) === 0 ) 以确保我实际上得到的是 0 而不是别的东西。没有效果。

  • 我在脚本顶部添加了set_time_limit( 900 )(并记录了它以确保它有效)以确保 cron 脚本有足够的时间执行。

  • 我添加了一个带有max_execution_time = 120error_log = /home/[[user]]/html/php_error.log 的.user.ini。我希望增加全局的最大执行时间可能会有所帮助,以防它是 post_exists 函数或其他超时的东西,但它似乎没有任何效果。 (客户端使用 GoDaddy 的托管 WordPress 计划,因此我的服务器配置和访问选项有点受限。.user.ini 文件是 GoDaddy 所说的进行 PHP 配置的方式,它应该每 5 分钟检查一次文件.)

  • 我添加了更多日志语句以查看到底发生了什么,这帮助我缩小了问题的范围,但我仍然不知道如何实际解决它。

【问题讨论】:

    标签: php wordpress cron


    【解决方案1】:

    这 30 秒在我看来很像默认的 php 执行时间。

    我不知道 wordpress cron 的内部结构,但我可以想象如果它失败(例如运行到 max_execution_time)它只是再次启动作业。

    您可以通过添加来仔细检查执行时间是否设置正确

    ini_get('max_execution_time');
    

    到您的日志文件,甚至添加关闭处理程序以查看程序是否因任何其他原因中止:

    register_shutdown_function( 
     function(){ 
         echo "Shutdown.".print_r(error_get_last(),true);
     });
    

    这可能与并发有关。您可以通过将一些随机字符串添加到每个请求生成一次的日志消息中来检查这一点(或者触发这些 cronjobs)。

    一般:

    如果您遇到执行时间的限制(无论是配置还是其他资源的其他限制),您总是可以尝试将问题拆分为更小的块。

    例如,您可以运行您的抓取工具,将输出序列化为某个临时文件,然后将该文件加载到另一个只需要读取该文件的任务中。

    如果这还不够,您可以进一步拆分您的问题(即让抓取工具可恢复或知道已经访问过的内容,因此它只需要解析部分数据)。

    【讨论】:

    • 感谢您的建议!澄清一下,这不是使用 WordPress cron(仅在有人访问该站点时执行)。由于 GoDaddy 的限制,我实际上不得不使用 cron-job.org 来设置自定义 cron 作业。我认为将任务分成两个独立的工作可能会奏效。
    • 如果您碰巧发现了这种奇怪行为的原因,请告诉我!
    猜你喜欢
    • 1970-01-01
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-18
    • 1970-01-01
    • 2021-10-16
    相关资源
    最近更新 更多