Laravel 5.1 连接到 Azure Web 作业时查询数据库的后台任务无法运行
Laravel 5.1 Background Task that Queries Database Fails to Work when hooked to an Azure Web Job
我在 Azure 上使用 WebJobs 执行 运行 Laravel 后台任务时遇到一个奇怪的问题。
我的 Laravel ExpireContactsFromDatabase 命令的 handle() 方法中有这段代码
public function handle()
{
* Update contacts that are old and past their expiry date but that have not been deleted
* Set their deleted at to the current timestamp
*/
$contact = Contact::where('expiry_date', '<=', date('Y-m-d H:i:s'))
->whereNull('deleted_at')
->update(array('deleted_at' => date('Y-m-d H:i:s')));
Log::info("200" . " " . "Contacts clearing executed successfully, see response from db :::: " . serialize($contact));
}
我已经在app\Console\Kernel.php成功注册了这个命令,像这样:
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
Inspire::class,
ExpireContactsFromDatabase::class,
];
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('inspire')
->hourly();
$schedule->command('expire:contacts')
->everyMinute()
->sendOutputTo('expired_contacts_results_dbresponse.txt');
}
}
这 运行 在我的本地开发机器上运行得很好。我在笔记本电脑上配置了一个 cron 作业,它会执行此命令并按预期使旧联系人过期。
当我将应用程序从本地主机迁移到 Ms Azure 时出现问题。我将 WebJob 配置为连续 运行,为其提供 artisan 的路径并发布时间表 运行。我使用 .bat 文件执行此操作,如下所示:
php D:\home\site\wwwroot\artisan schedule:run > D:\home\site\wwwroot\expired_contacts_results_confirmation.txt
PHP 在我的 Web 应用程序路径上,所以不用担心。
挑战是当命令执行时/当我 运行 php artisan schedule::run
并检查我的日志文件时,我看到来自数据库的响应(登录到 expired_contacts_results_dbresponse.txt)如下:
[2016-10-20 12:21:43] local.ERROR: exception 'PDOException' with message 'SQLSTATE[HY000] [2002] An attempt was made to access a socket in a way forbidden by its access permissions.
' in D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Connectors\Connector.php:55
我的猜测是 laravel 在这种情况下连接到数据库的方式有问题。但是,我的应用程序的其他组件使用相同的连接代码并且它们运行良好,所以我很困惑。在互联网上搜索此问题的确切解决方案并没有奏效。
我正在 运行通过 D1 共享托管计划在 Azure 上安装我的应用程序,并使用方便的 Azure MySQLInApp 数据库存储我的数据库。
这是我的完整堆栈跟踪。
Stack trace:
#0 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Connectors\Connector.php(55): PDO->__construct('mysql:host=;dbn...', '', '', Array)
#1 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Connectors\MySqlConnector.php(22): Illuminate\Database\Connectors\Connector->createConnection('mysql:host=;dbn...', Array, Array)
#2 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Connectors\ConnectionFactory.php(60): Illuminate\Database\Connectors\MySqlConnector->connect(Array)
#3 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Connectors\ConnectionFactory.php(49): Illuminate\Database\Connectors\ConnectionFactory->createSingleConnection(Array)
#4 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\DatabaseManager.php(175): Illuminate\Database\Connectors\ConnectionFactory->make(Array, 'mysql')
#5 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\DatabaseManager.php(67): Illuminate\Database\DatabaseManager->makeConnection('mysql')
#6 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php(3224): Illuminate\Database\DatabaseManager->connection(NULL)
#7 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php(3190): Illuminate\Database\Eloquent\Model::resolveConnection(NULL)
#8 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php(1870): Illuminate\Database\Eloquent\Model->getConnection()
#9 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php(1813): Illuminate\Database\Eloquent\Model->newBaseQueryBuilder()
#10 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php(1787): Illuminate\Database\Eloquent\Model->newQueryWithoutScopes()
#11 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php(3442): Illuminate\Database\Eloquent\Model->newQuery()
#12 [internal function]: Illuminate\Database\Eloquent\Model->__call('where', Array)
#13 [internal function]: App\Contact->where('expiry_date', '<=', '2016-10-20 12:2...')
#14 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php(3458): call_user_func_array(Array, Array)
#15 D:\home\site\wwwroot\app\Console\Commands\ExpireContactsFromDatabase.php(53): Illuminate\Database\Eloquent\Model::__callStatic('where', Array)
#16 D:\home\site\wwwroot\app\Console\Commands\ExpireContactsFromDatabase.php(53): App\Contact::where('expiry_date', '<=', '2016-10-20 12:2...')
#17 [internal function]: App\Console\Commands\ExpireContactsFromDatabase->handle()
#18 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Container\Container.php(507): call_user_func_array(Array, Array)
#19 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Console\Command.php(150): Illuminate\Container\Container->call(Array)
#20 D:\home\site\wwwroot\vendor\symfony\console\Command\Command.php(256): Illuminate\Console\Command->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#21 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Console\Command.php(136): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#22 D:\home\site\wwwroot\vendor\symfony\console\Application.php(846): Illuminate\Console\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#23 D:\home\site\wwwroot\vendor\symfony\console\Application.php(190): Symfony\Component\Console\Application->doRunCommand(Object(App\Console\Commands\ExpireContactsFromDatabase), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#24 D:\home\site\wwwroot\vendor\symfony\console\Application.php(121): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#25 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Foundation\Console\Kernel.php(107): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#26 D:\home\site\wwwroot\artisan(36): Illuminate\Foundation\Console\Kernel->handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
非常感谢我能得到的任何帮助。
Web App 中的内部 PHP 运行时似乎没有足够的权限访问 App 中的 MySQL。在我的测试中,我什至利用 Get the database connection string 处的测试连接代码创建了一个测试脚本,并在 KUDU 控制台站点中执行 PHP test.php
,我也会遇到同样的问题。
但如果我通过 HTTP 请求访问它(将通过 IIS 处理),它工作正常。因此,请尝试以下解决方法。实现您的功能并公开为 Restful API。在 Webjob 脚本中,您可以生成一个 HTTP 请求来调用此 API。
如有任何疑问,请随时告诉我。
该方案受支持 - 请参阅 this。我们正在努力改善这种情况。
我在 Azure 上使用 WebJobs 执行 运行 Laravel 后台任务时遇到一个奇怪的问题。
我的 Laravel ExpireContactsFromDatabase 命令的 handle() 方法中有这段代码
public function handle()
{
* Update contacts that are old and past their expiry date but that have not been deleted
* Set their deleted at to the current timestamp
*/
$contact = Contact::where('expiry_date', '<=', date('Y-m-d H:i:s'))
->whereNull('deleted_at')
->update(array('deleted_at' => date('Y-m-d H:i:s')));
Log::info("200" . " " . "Contacts clearing executed successfully, see response from db :::: " . serialize($contact));
}
我已经在app\Console\Kernel.php成功注册了这个命令,像这样:
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
Inspire::class,
ExpireContactsFromDatabase::class,
];
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('inspire')
->hourly();
$schedule->command('expire:contacts')
->everyMinute()
->sendOutputTo('expired_contacts_results_dbresponse.txt');
}
}
这 运行 在我的本地开发机器上运行得很好。我在笔记本电脑上配置了一个 cron 作业,它会执行此命令并按预期使旧联系人过期。
当我将应用程序从本地主机迁移到 Ms Azure 时出现问题。我将 WebJob 配置为连续 运行,为其提供 artisan 的路径并发布时间表 运行。我使用 .bat 文件执行此操作,如下所示:
php D:\home\site\wwwroot\artisan schedule:run > D:\home\site\wwwroot\expired_contacts_results_confirmation.txt
PHP 在我的 Web 应用程序路径上,所以不用担心。
挑战是当命令执行时/当我 运行 php artisan schedule::run
并检查我的日志文件时,我看到来自数据库的响应(登录到 expired_contacts_results_dbresponse.txt)如下:
[2016-10-20 12:21:43] local.ERROR: exception 'PDOException' with message 'SQLSTATE[HY000] [2002] An attempt was made to access a socket in a way forbidden by its access permissions.
' in D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Connectors\Connector.php:55
我的猜测是 laravel 在这种情况下连接到数据库的方式有问题。但是,我的应用程序的其他组件使用相同的连接代码并且它们运行良好,所以我很困惑。在互联网上搜索此问题的确切解决方案并没有奏效。
我正在 运行通过 D1 共享托管计划在 Azure 上安装我的应用程序,并使用方便的 Azure MySQLInApp 数据库存储我的数据库。
这是我的完整堆栈跟踪。
Stack trace:
#0 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Connectors\Connector.php(55): PDO->__construct('mysql:host=;dbn...', '', '', Array)
#1 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Connectors\MySqlConnector.php(22): Illuminate\Database\Connectors\Connector->createConnection('mysql:host=;dbn...', Array, Array)
#2 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Connectors\ConnectionFactory.php(60): Illuminate\Database\Connectors\MySqlConnector->connect(Array)
#3 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Connectors\ConnectionFactory.php(49): Illuminate\Database\Connectors\ConnectionFactory->createSingleConnection(Array)
#4 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\DatabaseManager.php(175): Illuminate\Database\Connectors\ConnectionFactory->make(Array, 'mysql')
#5 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\DatabaseManager.php(67): Illuminate\Database\DatabaseManager->makeConnection('mysql')
#6 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php(3224): Illuminate\Database\DatabaseManager->connection(NULL)
#7 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php(3190): Illuminate\Database\Eloquent\Model::resolveConnection(NULL)
#8 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php(1870): Illuminate\Database\Eloquent\Model->getConnection()
#9 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php(1813): Illuminate\Database\Eloquent\Model->newBaseQueryBuilder()
#10 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php(1787): Illuminate\Database\Eloquent\Model->newQueryWithoutScopes()
#11 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php(3442): Illuminate\Database\Eloquent\Model->newQuery()
#12 [internal function]: Illuminate\Database\Eloquent\Model->__call('where', Array)
#13 [internal function]: App\Contact->where('expiry_date', '<=', '2016-10-20 12:2...')
#14 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php(3458): call_user_func_array(Array, Array)
#15 D:\home\site\wwwroot\app\Console\Commands\ExpireContactsFromDatabase.php(53): Illuminate\Database\Eloquent\Model::__callStatic('where', Array)
#16 D:\home\site\wwwroot\app\Console\Commands\ExpireContactsFromDatabase.php(53): App\Contact::where('expiry_date', '<=', '2016-10-20 12:2...')
#17 [internal function]: App\Console\Commands\ExpireContactsFromDatabase->handle()
#18 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Container\Container.php(507): call_user_func_array(Array, Array)
#19 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Console\Command.php(150): Illuminate\Container\Container->call(Array)
#20 D:\home\site\wwwroot\vendor\symfony\console\Command\Command.php(256): Illuminate\Console\Command->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#21 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Console\Command.php(136): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#22 D:\home\site\wwwroot\vendor\symfony\console\Application.php(846): Illuminate\Console\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#23 D:\home\site\wwwroot\vendor\symfony\console\Application.php(190): Symfony\Component\Console\Application->doRunCommand(Object(App\Console\Commands\ExpireContactsFromDatabase), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#24 D:\home\site\wwwroot\vendor\symfony\console\Application.php(121): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#25 D:\home\site\wwwroot\vendor\laravel\framework\src\Illuminate\Foundation\Console\Kernel.php(107): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#26 D:\home\site\wwwroot\artisan(36): Illuminate\Foundation\Console\Kernel->handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
非常感谢我能得到的任何帮助。
Web App 中的内部 PHP 运行时似乎没有足够的权限访问 App 中的 MySQL。在我的测试中,我什至利用 Get the database connection string 处的测试连接代码创建了一个测试脚本,并在 KUDU 控制台站点中执行 PHP test.php
,我也会遇到同样的问题。
但如果我通过 HTTP 请求访问它(将通过 IIS 处理),它工作正常。因此,请尝试以下解决方法。实现您的功能并公开为 Restful API。在 Webjob 脚本中,您可以生成一个 HTTP 请求来调用此 API。
如有任何疑问,请随时告诉我。
该方案受支持 - 请参阅 this。我们正在努力改善这种情况。