Moses Ndeda Moses Ndeda - 18 days ago 11
MySQL Question

Laravel 5.1 Background Task that Queries Database Fails to Work when hooked to an Azure Web Job

I am having a strange problem using WebJobs on Azure to run Laravel Background tasks.

I have this code in my Laravel ExpireContactsFromDatabase command's handle() method

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));

}


I have successfully registered this command in app\Console\Kernel.php, like so:

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');

}
}


This is running very well on my local development machine. I configured a cron job on my laptop and it executes this command and expires the old contacts as expected.

The problem comes in when I migrate the application from localhost to Ms Azure. I configure a WebJob to run continuosly, give it the path to artisan and issue schedule run. I do this in using a .bat file, like so:

php D:\home\site\wwwroot\artisan schedule:run > D:\home\site\wwwroot\expired_contacts_results_confirmation.txt


PHP is on my web applications path so no worries.

The challenge is when the command executes/ when I run
php artisan schedule::run
and I check my log files, I see the response from the database (logged into expired_contacts_results_dbresponse.txt) as follows:

[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


My guess is that the way laravel is connecting to the database has issues in this case. However, other components of my application use the same connection codes and they are working well so In am confused. Scouring the internet for an exact solution to this problem has not worked.

I am running my app on Azure on the D1 Shared Hosting Plan and using the convenient Azure MySQLInApp database for my database storage.

Here is my full stack trace.

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))


Will greatly appreciate any help I can get.

Answer

It seems the internal PHP runtime in Web App doesn't have sufficient permission to access to MySQL in App. In my test, I even create a test script leveraging the test connection code at Get the database connection string, and execute PHP test.php in KUDU console site, I would get the same issue with you.

But it worked fine if I access it via HTTP request (Which will be handled via IIS). So please try the following workaround. Implementing your functionality and expose as a Restful API. In Webjob script, you can generate a HTTP request to call this API.

Any further concern, please feel free to let me know.