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

Always base the timeout duration on the configured Lambda timeout #3

Merged
merged 7 commits into from
Mar 30, 2021

Conversation

mnapoli
Copy link

@mnapoli mnapoli commented Mar 26, 2021

I'll detail the changes in the diff

application took more time than expected.

In the vast majority of cases, it is an external call to a database, cache or API
that is stuck waiting for IO.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've moved this section up and merged it with previous paragraphs


## Catching the exception

If you are using a framework, then the framework is probably catching all exceptions
and displays an error page for the users. You may of course catch the exception
yourself:
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I clarified this to separate php-XX users and php-XX-fpm users, because framework users on FPM could have been confused by the example with the Lambda handler below

src/Timeout/Timeout.php Outdated Show resolved Hide resolved
$this->assertEquals(5, $getTimeout(LambdaRuntime::fromEnvironmentVariable()));
$this->assertEquals(-1, $getTimeout(LambdaRuntime::fromEnvironmentVariable(-1)));
$this->assertEquals(0, $getTimeout(LambdaRuntime::fromEnvironmentVariable(0)));
$this->assertEquals(10, $getTimeout(LambdaRuntime::fromEnvironmentVariable(10)));
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turned it into a functional test just so that we sleep better at night 😄

}
if (self::isListening()) {
throw new \RuntimeException('Unable to stop node.js server');
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I started having some weird things happen at some point, not related to the PR sorry!

I think I had a leftover process, so I added some more checks here to make sure we successfully kill the test server.

. self::$port . ' >> /tmp/server.log 2>&1 &');
self::wait();
if (self::isListening()) {
throw new \Exception('Server is already running');
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

@@ -445,7 +445,6 @@
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"dev": true,
"dependencies": {
"graceful-fs": "^4.1.6",
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Argh sorry, not related. I've been having this line change every time I preview the documentation locally. It finally managed to find its way into a commit, my bad. Let's ignore this.

Copy link
Owner

@Nyholm Nyholm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. Most looks okey. But there is a nasty bug with the FPM thing.

If you test it, it will work until first timeout, then it will never handle a timeout properly again.

runtime/layers/fpm/bootstrap Show resolved Hide resolved
{
if ($apiUrl === '') {
die('At the moment lambdas can only be executed in an Lambda environment');
}

$this->apiUrl = $apiUrl;
$this->invoker = new Invoker;
$this->timeout = $timeout;
$this->enableTimeout = (getenv('BREF_FEATURE_TIMEOUT') !== false);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I strongly think we should be able to construct a LambdaRuntime without using environment variables. That will make testing easier, allow us to be thread safe and give the creator more control.

I suggest moving this to a named factory method.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I see. TBH my goal is to have simple logic. If we have an internal boolean flag to control the timeout, that means we have 2 different options for the same thing:

  • the boolean flag
  • the boolean BREF_FEATURE_TIMEOUT env variable

That makes 4 possible combinations, instead of 2. Not much, but 2 possibilities are simpler to deal with than 4.

What would we gain if we added this little extra complexity? I don't think testing would be impacted, given tests already exist and work. I'm also happy if I can write tests as high level as possible (using the same API as users when possible).

Regarding thread safety, I don't see where multithreading the lambda runtime class would be used in the wild. We could also solve that by using $_SERVER if that ever happens.

So to me it boils down to: there's a single feature flag for the feature instead of 2.

Copy link
Owner

@Nyholm Nyholm Mar 28, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that you would like to have simplicity.

I still think it is a mistake to let a class' internal behaviour to be affected by the global state. I dont follow your logic about the increased combinations. What I suggest is the following:

     public static function fromEnvironmentVariable(): self
    {
        return new self((string) getenv('AWS_LAMBDA_RUNTIME_API'), getenv('BREF_FEATURE_TIMEOUT') !== false);
    }

    public function __construct(string $apiUrl, bool $enableTimeout /* maybe a default value */)
    {
        if ($apiUrl === '') {
            die('At the moment lambdas can only be executed in an Lambda environment');
        }

        $this->apiUrl = $apiUrl;
        $this->invoker = new Invoker;
        $this->enableTimeout = $enableTimeout;
    }

Copy link
Author

@mnapoli mnapoli Mar 28, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK I see, with the example indeed it's more concise that what I pictured, thanks.

I tried to go with it, but that got me here:

image

On one hand, that's cool because I can get rid of changing the global state for the tests, and pass true/false explicitly.

But on the other hand, what I want to test is that the BREF_FEATURE_TIMEOUT setting actually works. So I want to do a very high level test, I consider it definitely ok here to change the environment variable because I would be testing the same API that end users actually use.

FTR I was going to say there's no downside, but the last commit I just pushed will show that it's not true: I have to be careful resetting the global state. But it still feels more comfortable with a higher level test here.

src/Timeout/Timeout.php Outdated Show resolved Hide resolved
@Nyholm Nyholm merged commit 0b6d7b2 into Nyholm:timeouts Mar 30, 2021
@mnapoli mnapoli deleted the timeouts-feature-flag branch March 30, 2021 09:44
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

Successfully merging this pull request may close these issues.

2 participants