【问题标题】:Laravel 5 concurrent request and scheduled jobLaravel 5并发请求和计划作业
【发布时间】:2016-11-23 04:25:52
【问题描述】:

我将Laravel 5php 5.5.9-1ubuntu4.14mysql 5.5.47 一起使用。 我有一个多租户环境,每个租户都有一个单独的数据库。因此,对于每个 HTTP 请求,我都会在 BeforeMiddleware 中设置适当的数据库连接,就像这样

public function handle($request, Closure $next)
{
...
// Set the client DB name and fire it up as the new default DB connection
Config::set('database.connections.mysql_client.host', $db_host);
Config::set('database.connections.mysql_client.database', $db_database);
Config::set('database.connections.mysql_client.username', $db_username);
Config::set('database.connections.mysql_client.password', $db_password);
DB::setDefaultConnection('mysql_client');
...
}

即使对于并发 HTTP 请求,这也能正常工作。

但现在我想将计划作业添加到我的应用程序中。这些作业将向属于所有租户的用户发送通知。所以,我再次需要连接到各自的租户数据库。但此连接不会通过 HTTP 请求。假设我有一个 CommunicationController 和一个用于发送通知的函数。

public function sendNotification()
{
  ...
  DB::purge('mysql_client');//IMP
  // Set the client DB name and fire it up as the new default DB connection
  Config::set('database.connections.mysql_client.host', $db_host);
  Config::set('database.connections.mysql_client.database', $db_database);
  Config::set('database.connections.mysql_client.username', $db_username);
  Config::set('database.connections.mysql_client.password', $db_password);

  DB::setDefaultConnection('mysql_client');
  ...
}

这是我设置Config 值的地方。该函数将通过Laravel Scheduler每分钟执行一次。

我的问题是:

  • HTTP 请求进来时会发生什么?会不会有 在 HTTP 请求和计划作业中都设置了 Config 参数的并发问题?
  • 如果 HTTP 请求与计划作业同时运行,它是否会连接到某些不正确的数据库?

【问题讨论】:

    标签: php mysql laravel laravel-5


    【解决方案1】:

    根据Laravel docs

    在运行时设置的配置值仅为 当前请求,不会转移到后续请求中。

    配置值是在您专门调用 Config::set 方法时在运行时设置的,因此该值仅对当前请求有效,因此您永远不会遇到任何并发问题。

    你的第二个问题也是不可能的。即使您之前的任务正在数据库上运行请求,第二个/后续任务也会等待数据库上的锁(如果有)被释放。您应该尝试确保您没有通过使用多插入、sqldump(如果您正在执行大型查询)等方式执行任何可以在数据库上长时间锁定的查询。

    【讨论】:

    • 是的,我知道配置值仅针对当前请求设置。但我的信念是,这仅适用于 HTTP 请求。我的问题是,当 HTTP 请求和预定命令同时运行时会发生什么。但现在很清楚了。通过查看代码,我确信不会有任何并发​​问题。
    【解决方案2】:

    查看Illuminate\Config\Repository,它是用于Config门面的实现,特别是set方法

    public function set($key, $value = null)
    {
        if (is_array($key)) {
            foreach ($key as $innerKey => $innerValue) {
                Arr::set($this->items, $innerKey, $innerValue);
            }
        } else {
            Arr::set($this->items, $key, $value);
        }
    }
    

    您可以放心,该集不是 IO 集(即文件系统),而是一个内存集。因此,每分钟运行的 CLI 调度程序命令将像所有其他 http 请求一样在其自己的上下文中运行。

    【讨论】:

      猜你喜欢
      • 2017-07-07
      • 2021-06-13
      • 2015-11-13
      • 1970-01-01
      • 2017-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多