Skip to content

Commit f44a70b

Browse files
authored
Merge pull request #110 from fnproject/issue-103
Fix "None-None" race condition with keep-alive timeout
2 parents 035a3c5 + 0a6a952 commit f44a70b

3 files changed

Lines changed: 60 additions & 5 deletions

File tree

fdk/async_http/protocol.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,15 @@ def response_timeout_callback(self):
228228
self._request_handler_task.cancel()
229229
self.write_error(ServiceUnavailable("Response Timeout"))
230230

231+
def keep_alive_time_left(self):
232+
"""
233+
Return keep alive time remaining, zero if no response written yet.
234+
"""
235+
if self._last_response_time and current_time:
236+
time_elapsed = current_time - self._last_response_time
237+
return self.keep_alive_timeout - time_elapsed
238+
return 0
239+
231240
def keep_alive_timeout_callback(self):
232241
"""
233242
Check if elapsed time since last response exceeds our configured
@@ -236,9 +245,8 @@ def keep_alive_timeout_callback(self):
236245
237246
:return: None
238247
"""
239-
time_elapsed = current_time - self._last_response_time
240-
if time_elapsed < self.keep_alive_timeout:
241-
time_left = self.keep_alive_timeout - time_elapsed
248+
time_left = self.keep_alive_time_left()
249+
if time_left >= 0:
242250
self._keep_alive_timeout_handler = self.loop.call_later(
243251
time_left, self.keep_alive_timeout_callback
244252
)
@@ -431,10 +439,10 @@ def write_response(self, response):
431439
self.transport.close()
432440
self.transport = None
433441
else:
442+
self._last_response_time = current_time
434443
self._keep_alive_timeout_handler = self.loop.call_later(
435444
self.keep_alive_timeout, self.keep_alive_timeout_callback
436445
)
437-
self._last_response_time = current_time
438446
self.cleanup()
439447

440448
async def drain(self):
@@ -483,10 +491,10 @@ async def stream_response(self, response):
483491
self.transport.close()
484492
self.transport = None
485493
else:
494+
self._last_response_time = current_time
486495
self._keep_alive_timeout_handler = self.loop.call_later(
487496
self.keep_alive_timeout, self.keep_alive_timeout_callback
488497
)
489-
self._last_response_time = current_time
490498
self.cleanup()
491499

492500
def write_error(self, exception):

fdk/async_http/signpost.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
This code is from https://github.com/huge-success/sanic/
2+
3+
It's modified and stripped-down because importing full sanic
4+
increased cold starts.
5+
6+
See https://github.com/fnproject/fdk-python/pull/60 for context.

fdk/tests/test_protocol.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4+
# not use this file except in compliance with the License. You may obtain
5+
# a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.
14+
15+
from fdk.async_http import protocol
16+
17+
18+
def http_protocol(**kwargs):
19+
return protocol.HttpProtocol(
20+
loop=None, request_handler=None, error_handler=None,
21+
**kwargs)
22+
23+
24+
def test_keep_alive_time_left_before_time_is_set():
25+
p = http_protocol()
26+
27+
protocol.current_time = None
28+
p._last_request_time = None
29+
30+
time_left = p.keep_alive_time_left()
31+
assert 0 == time_left
32+
33+
34+
def test_keep_alive_time_left_after_time_is_set():
35+
p = http_protocol(keep_alive_timeout=15)
36+
37+
protocol.current_time = 96
38+
p._last_response_time = 64
39+
40+
time_left = p.keep_alive_time_left()
41+
assert 15 - 32 == time_left

0 commit comments

Comments
 (0)