Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 在具有会话的web应用程序中处理耗时长的ajax调用_Php_Web_Timeout_Single Page Application_Background Process - Fatal编程技术网

Php 在具有会话的web应用程序中处理耗时长的ajax调用

Php 在具有会话的web应用程序中处理耗时长的ajax调用,php,web,timeout,single-page-application,background-process,Php,Web,Timeout,Single Page Application,Background Process,我非常想重新考虑一下我在web应用程序中实现的处理很长进程的方法 问题 我有一个用javascript编写的web应用程序,它通过API与服务器通信。此应用程序有一些“批量操作”,需要花费大量时间来执行。我希望以一种安全的方式执行它们,确保服务器不会超时,并向用户提供丰富的反馈,以便用户知道发生了什么 通常的方法 正如我在研究中所看到的,推荐的方法是在服务器中启动一个后台进程,让它在某个地方写下运行情况,这样您就可以请求检查它并向用户提供反馈。由于Im在后端使用php,因此该方法大致如下所述:

我非常想重新考虑一下我在web应用程序中实现的处理很长进程的方法

问题

我有一个用javascript编写的web应用程序,它通过API与服务器通信。此应用程序有一些“批量操作”,需要花费大量时间来执行。我希望以一种安全的方式执行它们,确保服务器不会超时,并向用户提供丰富的反馈,以便用户知道发生了什么

通常的方法

正如我在研究中所看到的,推荐的方法是在服务器中启动一个后台进程,让它在某个地方写下运行情况,这样您就可以请求检查它并向用户提供反馈。由于Im在后端使用php,因此该方法大致如下所述:

添加一些必要条件

由于我正在开发一个开源项目(WordPress插件),我希望它能在各种情况和环境下工作。我不想添加服务器端需求,而且据我所知,后台处理方法可能无法在几个共享托管解决方案中工作

我希望它能够开箱即用,在(几乎)任何具有典型WordPress支持的服务器上运行,即使它最终成为一个稍微慢一点的解决方案

我的方法

我们的想法是以一种方式打破这个过程,它将通过许多小请求以增量方式运行

因此,当浏览器第一次发送运行流程的请求时,它只会运行其中的一小步,并返回有用的信息以向用户提供一些反馈。然后浏览器执行另一个请求,并重复该请求,直到服务器通知该过程已完成

为了做到这一点,我将把这个对象存储在一个会话中,因此第一个请求将给我一个id,下面的请求将把这个id发送给服务器,以便它操作同一个对象

以下是一个概念性示例:

class LongProcess {

    function __construct() {

        $this->id = uniqid();
        $_SESSION[$this->id] = $this;
        $this->step = 1;
        $this->total = 100;

    }


    function run() {
        // do stuff based on the step you are in
        $this->step = $this->step + 10;
        if ($this->step >= $this->total)
            return -1;
        return $this->step;
    }

}

function ajax_callback() {

    session_start();

    if (!isset($_POST['id']) || empty($_POST['id'])) {
        $object = new LongProcess();
    } else {
        $object = $_SESSION[$_POST['id']];
    }

    $step = $object->run();

    echo json_encode([
        'id' => $object->id,
        'step' => $return,
        'total' => $object->total
    ]);

}
有了它,我可以让我的客户机递归地发送请求,并在收到响应时更新对用户的反馈

    function recursively_ajax(session_id)
    {
        $.ajax({
            type:"POST",
            async:false, // set async false to wait for previous response
            url: "xxx-ajax.php",
            dataType:"json",
            data:{
                action: 'bulk_edit',
                id: session_id
            },
            success: function(data)
            {
                updateFeedback(data);
                if(data.step != -1){
                    recursively_ajax(data.id);
                } else {
                    updateFeedback('finish');
                }
            }
        });
    }  

    $('#button').click(function() {
        recursively_ajax(); 
    });
当然,这只是一个概念证明,我甚至没有在实际代码中使用jQuery。这只是为了表达这个想法

请注意,存储在会话中的这个对象应该是一个非常轻量级的对象。任何正在处理的实际数据都应该存储在数据库或文件系统中,并且只在对象中引用它,以便它知道在哪里查找内容

一个典型的例子是处理一个大的CSV文件。文件将存储在文件系统中,对象将存储一个指向最后处理的行的指针,以便知道下一个请求从何处开始

该对象还可能返回一个更详细的日志,描述所做的一切并报告错误,以便用户完全了解所做的事情

我认为最好的界面是一个带有“查看详细信息”按钮的进度条,它可以打开一个包含详细日志的文本区域

这有意义吗?

所以现在我问。看起来怎么样?这是一个可行的方法吗


有没有更好的方法来做到这一点并确保它在非常有限的服务器上工作?

您的方法有几个缺点:

  • 您的大量请求可能会阻止其他请求。通常,处理web请求的并发PHP进程是有限的。如果限制为10,并且所有时间段都是通过处理您的大量请求而占用的,那么您的网站将无法工作,直到其中一些请求完成释放另一个轻量级请求的时间段

  • 你(可能)无法估计完成一步需要多少时间。根据服务器负载的不同,可能需要5秒或50秒。50秒可能会超过大多数共享人质的执行时间限制

  • 此任务将由客户端控制-客户端的任何中断(网络问题,关闭浏览器选项卡)都将中断任务

  • 根据会话后端,使用会话存储当前状态可能会导致竞争条件错误-来自同一客户端的并发请求可能会覆盖后台任务在会话中所做的更改。默认情况下,PHP对会话使用锁定,所以情况不应该是这样,但是如果有人在没有锁定的情况下对会话使用备用后端(DB、redis),这将导致严重且难以调试的错误

  • 这里有一个明显的权衡。对于那些优先考虑简化安装和配置的小型网站,您的方法是可以的。在任何其他情况下,我都会坚持使用简单的基于cron的队列在后台运行任务,并使用AJAX请求仅检索任务的当前状态。到目前为止,我还没有看到没有cron支持的托管和向cron添加任务对最终用户来说应该不是那么困难(有适当的文档)


    在这两种情况下,我都不会将会话用作存储。将任务及其状态保存在数据库中,并使用一些锁定系统来确保只有一个进程可以修改一个任务的数据。这将比使用会话更加健壮和灵活。

    感谢您的所有输入。我只想在这里记录我得到的一些非常好的答案

    一些名为Woocommerce的WordPress插件已经合并了来自“WP后台处理”库的代码,该库不再是Mantain,而是通过一些重要的改进实现了Cron方法。请参阅此博客帖子:

    真正的图书馆就住在这里:

    虽然这是一个特定于WordPress的库,但我认为这种方法适用于任何情况

    对于WordPress,还有一个名为Action Scheduler的库,它不仅可以在后台处理tun进程,还允许您对它们进行调度。值得一看:


    您的描述非常笼统,因此很难给出建议。例如,是否有必要