Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error on multiple ajax requests #24510

Closed
Muhammadinaam opened this issue Jun 8, 2018 · 12 comments
Closed

Error on multiple ajax requests #24510

Muhammadinaam opened this issue Jun 8, 2018 · 12 comments

Comments

@Muhammadinaam
Copy link

Muhammadinaam commented Jun 8, 2018

  • Laravel Version: 5.4
  • PHP Version: 7.1
  • Database Driver & Version:

Description:

In case of multiple ajax requests at the same time (I have 3 ajax requests in $(document).ready() ), then following two errors occur sometimes (errors occur sometimes, not every time).

1. 500 Internal Server Error
500 internal server error occurs without any information about error (see the image below)

image

First few lines of log file are given below:
[2018-06-08 12:42:21] true.ERROR: RuntimeException: The only supported ciphers are AES-128-CBC and AES-256-CBC with the correct key lengths. in G:\xampp\htdocs\cosmo\36-mentis-bugs-fixes-20-12-2017\vendor\laravel\framework\src\Illuminate\Encryption\Encrypter.php:43

Log file of above error is attached
laravel-2018-06-08.log

According to log file, it seems that in case of multiple ajax requests, Laravel is not able to read .env file correctly.

2. 401 Session Expired Error
In case of multiple ajax requests, session expires sometimes.

@jesseyofferenvan
Copy link

I'm pretty sure you haven't set up your .env file correctly yet, or at all.
Laravel ships with a .env.example file, rename this to .env, then make sure the APP_KEY is filled, when this is empty run the command below.

php artisan key:generate

@devcircus
Copy link
Contributor

The fact that the errors only occur sometimes would seem to say it's not an issue with the.env file.

@jesseyofferenvan
Copy link

Not exactly, this very much depends what the functions behind the calls do. If any of them try to interact with the database, without having the app_key, you get this exact error.

@sisve
Copy link
Contributor

sisve commented Jun 8, 2018

The fact that it occurs sometimes indicate that it is an issue with the .env file ... kind-of. Your paths indicate that you're using Apache on Windows, and I would guess that you haven't cached your configuration files.

This is a known issue, it just isn't documented. The dotenv library sets environment variables, and those are process-wide. Apache on Windows defaults to a mpm that executes several php requests in the same process, but in different threads. This means that any request will affect other concurrent requests. One request will see another requests environment variables, and other weird stuff. Who sees what depends on which requests are executing at any given time. And there's also weirdness when, at the end of a request, dotenv removes the set environment variables which means they are removed from other concurrently executing requests.

This becomes really visible when you host two separate sites, usually a frontend application another api application, when the environment variables differ between the applications. But this is not required to run into problems, two concurrent requests to the same application can still have issues depending on timing issues.

The other issue you mention with concurrent session access, this sounds like a known issue. Two concurrent will not cooperate when modifying the session content; the last one to save the session will "win" and override the entire session content.

Related issues:
#19454 (Laravel .env conflicts and overwrites between 2 laravel projects)
Two different projects under one server, happen .env conflict (Two different projects under one server, happen .env conflict)
#20207 (Other Laravel projects get failure when one of them calls an API)
#21727 (env() Helper Post php artisan config:cache)
vlucas/phpdotenv#76 (Changing process environment unsafe on multithreaded servers)
vlucas/phpdotenv#219 (When you have two or more sites on one server, the sites's .env will affect each other)

#5416 (Race condition on session engine causing unexpected behavior on concurrent requests)
#14385 (Concurrent requests wiping out the session)
#15760 (Session Persistance Issues)
#20579 (when I use huge requests I lose session auth)

@devcircus
Copy link
Contributor

Definitely could be this exact situation. I was referring to the previous post that suggested an application key had not been generated for the .env. In that case, it would NEVER work, as opposed to "sometimes".

@Muhammadinaam
Copy link
Author

What is the solution?

@matt-allan
Copy link
Contributor

What is the solution?

Assuming that you are running into the issue with getenv/putenv being called in threads your options are:

  1. Stop using a threaded web server. The PHP manual recommends against using a threaded MPM. Even if you compile PHP with thread safety it still calls functions that aren't thread safe and this problem will still happen. I explain this in depth in this article.
  2. Stop using environment variables. The problem should go away if you run config:cache. This works because when you cache the config Laravel will no longer call getenv and putenv during bootstrapping. The downside is you need to run config:cache again every time you change an environment variable or config setting. This doesn't solve the problem 100% because other libraries and PHP itself will still call getenv but it should avoid any Laravel specific issues.

there's also weirdness when, at the end of a request, dotenv removes the set environment variables which means they are removed from other concurrently executing requests.

@sisve is this the dotenv library clearing them? I was under the impression it was PHP itself clearing them out at the beginning/end of the request. I know FPM clears the environment but I'm not familiar with Apache.

@sisve
Copy link
Contributor

sisve commented May 20, 2019

@matt-allan I'm not sure where I got that information. I can't find any code that backs it up, but I'm pretty sure someone is clearing it.

I base that on the assumption that dotenv will only set variables that aren't already set (the way we call it), so if they weren't cleared people would be reporting problems with changes to the .env file not taking effect. The first request would set the environment variables, and no changes will take effect on future requests.

But I'm mostly basing this on assumptions on what I think would happen; I havn't verified this myself in any way.

@matt-allan
Copy link
Contributor

It's definitely being cleared but I don't think it's the dotenv library. The dotenv library has a clear function but I don't see it being called anywhere.

I am able to reproduce the issue (getenv returning false when the variable should be set) without a dotenv library using the following script:

<?php

putenv('FOO=BAR');

usleep(rand(100, 1000000));

var_dump(getenv('FOO'));

If you run this script with a ZTS build of PHP and a threaded web server like Apache with the worker MPM and then make a lot of concurrent requests you will see a lot of requests return bool(false).

The reason is explained well in this issue. Basically the value set with putenv is destroyed at the end of the request, even though another thread may have accessed it.

So basically this isn't a Laravel issue, it's a PHP issue. It's not really a PHP bug because:

  • The PHP manual clearly states you shouldn't be using a threaded MPM.
  • The glibc manual clearly states that multi-threaded programs shouldn't call putenv.

The issue is "fixed" on 7.4 but as explained in the comment it won't go away completely because PHP itself calls the libc functions getenv and putenv directly.

If you insist on using a threaded server anyway you will need to avoid calling putenv.

If you run the php artisan config:cache command and Laravel will not call putenv. This is the simplest solution and you should be using this for production anyway.

Alternatively you can avoid using a .env file and set the environment variables with Apache's SetEnv directive or via your operating system.

A third option is to override the bootstrapper to not call putenv.

<?php
// app/Bootstrap/LoadEnvironmentVariables.php

namespace App\Bootstrap;

use Dotenv\Dotenv;
use Dotenv\Environment\DotenvFactory;
use Dotenv\Environment\Adapter\EnvConstAdapter;
use Dotenv\Environment\Adapter\ServerConstAdapter;

class LoadEnvironmentVariables extends \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables
{
    /**
     * Create a Dotenv instance.
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @return \Dotenv\Dotenv
     */
    protected function createDotenv($app)
    {
        return Dotenv::create(
            $app->environmentPath(),
            $app->environmentFile(),
            new DotenvFactory([new EnvConstAdapter, new ServerConstAdapter])
        );
    }
}
// bootstrap/app.php
$app->singleton(
    \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
    App\Bootstrap\LoadEnvironmentVariables::class,
);

The downside of this approach is it will cause issues like #27828.

@lannodev
Copy link

@matt-allan There is a solution for lumen?

@matt-allan
Copy link
Contributor

@luciano-work easiest fix is probably to call this function in bootstrap/app.php before Lumen loads environment variables. However if any of your code is calling getenv instead of Laravel's env helper or $_ENV it's going to break.

<?php

require_once __DIR__.'/../vendor/autoload.php';

+ Illuminate\Support\Env::disablePutEnv();

(new Laravel\Lumen\Bootstrap\LoadEnvironmentVariables(
    dirname(__DIR__)
))->bootstrap();

@lannodev
Copy link

@matt-allan thank you for your support 👍🏻
To fix my problem I have change my server apache to use FastCGI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants