Skip to content

Commit f5271ce

Browse files
authored
Setting special limits for Python 3.6 and 3.7 (#890)
* Setting special limits for Python 3.[6|7] * Updated CODEOWNERS file
1 parent f5a68bd commit f5271ce

File tree

4 files changed

+60
-46
lines changed

4 files changed

+60
-46
lines changed

CODEOWNERS

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#
99
# AZURE FUNCTIONS TEAM
10-
# For all file changes, github would automatically include the following people in the PRs.
10+
# For all file changes, github would automatically
11+
# include the following people in the PRs.
1112
#
12-
* @anirudhgarg @Hazhzeng @vrdmr @AnatoliB
13+
* @vrdmr @AnatoliB

azure_functions_worker/constants.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
PYTHON_THREADPOOL_THREAD_COUNT_DEFAULT = 1
4040
PYTHON_THREADPOOL_THREAD_COUNT_MIN = 1
4141
PYTHON_THREADPOOL_THREAD_COUNT_MAX = sys.maxsize
42+
PYTHON_THREADPOOL_THREAD_COUNT_MAX_37 = 32
43+
4244
PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT = False
4345
PYTHON_ISOLATE_WORKER_DEPENDENCIES_DEFAULT_39 = False
4446
PYTHON_ENABLE_WORKER_EXTENSIONS_DEFAULT = False

azure_functions_worker/dispatcher.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from . import protos
2727
from .constants import (PYTHON_THREADPOOL_THREAD_COUNT,
2828
PYTHON_THREADPOOL_THREAD_COUNT_DEFAULT,
29-
PYTHON_THREADPOOL_THREAD_COUNT_MAX,
29+
PYTHON_THREADPOOL_THREAD_COUNT_MAX_37,
3030
PYTHON_THREADPOOL_THREAD_COUNT_MIN)
3131
from .logging import disable_console_logging, enable_console_logging
3232
from .logging import (logger, error_logger, is_system_log_category,
@@ -567,25 +567,28 @@ def tp_max_workers_validator(value: str) -> bool:
567567
'integer')
568568
return False
569569

570-
if int_value < PYTHON_THREADPOOL_THREAD_COUNT_MIN or (
571-
int_value > PYTHON_THREADPOOL_THREAD_COUNT_MAX):
570+
if int_value < PYTHON_THREADPOOL_THREAD_COUNT_MIN:
572571
logger.warning(f'{PYTHON_THREADPOOL_THREAD_COUNT} must be set '
573572
f'to a value between '
574573
f'{PYTHON_THREADPOOL_THREAD_COUNT_MIN} and '
575-
f'{PYTHON_THREADPOOL_THREAD_COUNT_MAX}. '
576-
'Reverting to default value for max_workers')
574+
'sys.maxint. Reverting to default value for '
575+
'max_workers')
577576
return False
578-
579577
return True
580578

581579
# Starting Python 3.9, worker won't be putting a limit on the
582580
# max_workers count in the created threadpool.
583581
default_value = None if sys.version_info.minor == 9 \
584582
else f'{PYTHON_THREADPOOL_THREAD_COUNT_DEFAULT}'
583+
585584
max_workers = get_app_setting(setting=PYTHON_THREADPOOL_THREAD_COUNT,
586585
default_value=default_value,
587586
validator=tp_max_workers_validator)
588587

588+
if sys.version_info.minor <= 7:
589+
max_workers = min(int(max_workers),
590+
PYTHON_THREADPOOL_THREAD_COUNT_MAX_37)
591+
589592
# We can box the app setting as int for earlier python versions.
590593
return int(max_workers) if max_workers else None
591594

tests/unittests/test_dispatcher.py

Lines changed: 46 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@
1111
from azure_functions_worker import testutils
1212
from azure_functions_worker.constants import PYTHON_THREADPOOL_THREAD_COUNT, \
1313
PYTHON_THREADPOOL_THREAD_COUNT_DEFAULT, \
14-
PYTHON_THREADPOOL_THREAD_COUNT_MAX, \
15-
PYTHON_THREADPOOL_THREAD_COUNT_MIN
14+
PYTHON_THREADPOOL_THREAD_COUNT_MAX_37, PYTHON_THREADPOOL_THREAD_COUNT_MIN
1615

1716
SysVersionInfo = col.namedtuple("VersionInfo", ["major", "minor", "micro",
1817
"releaselevel", "serial"])
@@ -37,7 +36,8 @@ def setUp(self):
3736
script_root=DISPATCHER_FUNCTIONS_DIR)
3837
self._default_workers: Optional[
3938
int] = PYTHON_THREADPOOL_THREAD_COUNT_DEFAULT
40-
self._allowed_max_workers: int = 100000
39+
self._over_max_workers: int = 10000
40+
self._allowed_max_workers: int = PYTHON_THREADPOOL_THREAD_COUNT_MAX_37
4141
self._pre_env = dict(os.environ)
4242
self.mock_version_info = patch(
4343
'azure_functions_worker.dispatcher.sys.version_info',
@@ -128,33 +128,26 @@ async def test_dispatcher_sync_threadpool_below_min_setting(self):
128128
await self._assert_workers_threadpool(self._ctrl, host,
129129
self._default_workers)
130130
mock_logger.warning.assert_any_call(
131-
f'{PYTHON_THREADPOOL_THREAD_COUNT} must be set to a value '
132-
f'between {PYTHON_THREADPOOL_THREAD_COUNT_MIN} and '
133-
f'{PYTHON_THREADPOOL_THREAD_COUNT_MAX}. Reverting to default '
134-
f'value for max_workers')
131+
f'{PYTHON_THREADPOOL_THREAD_COUNT} must be set '
132+
f'to a value between '
133+
f'{PYTHON_THREADPOOL_THREAD_COUNT_MIN} and '
134+
'sys.maxint. Reverting to default value for '
135+
'max_workers')
135136

136-
@unittest.skip("We no more check any max limit. This is up to the customer,"
137-
" how ever high int they want to set")
138137
async def test_dispatcher_sync_threadpool_exceed_max_setting(self):
139-
"""Test if the sync threadpool will pick up default value when the
138+
"""Test if the sync threadpool will pick up default max value when the
140139
setting is above maximum
141140
"""
142-
with patch('azure_functions_worker.dispatcher.logger') as mock_logger:
141+
with patch('azure_functions_worker.dispatcher.logger'):
143142
# Configure thread pool max worker to an invalid value
144143
os.environ.update({PYTHON_THREADPOOL_THREAD_COUNT:
145144
f'{self._over_max_workers}'})
146145
async with self._ctrl as host:
147146
await self._check_if_function_is_ok(host)
148147

149-
# Ensure the dispatcher sync threadpool should fallback to 1
148+
# Ensure the dispatcher sync threadpool should fallback to max
150149
await self._assert_workers_threadpool(self._ctrl, host,
151-
self._default_workers)
152-
153-
mock_logger.warning.assert_any_call(
154-
f'{PYTHON_THREADPOOL_THREAD_COUNT} must be set to a value '
155-
f'between {PYTHON_THREADPOOL_THREAD_COUNT_MIN} and '
156-
f'{PYTHON_THREADPOOL_THREAD_COUNT_MAX}. Reverting to default '
157-
f'value for max_workers')
150+
self._allowed_max_workers)
158151

159152
async def test_dispatcher_sync_threadpool_in_placeholder(self):
160153
"""Test if the sync threadpool will pick up app setting in placeholder
@@ -189,13 +182,13 @@ async def test_dispatcher_sync_threadpool_in_placeholder_invalid(self):
189182
mock_logger.warning.assert_any_call(
190183
f'{PYTHON_THREADPOOL_THREAD_COUNT} must be an integer')
191184

192-
@unittest.skip("We no more check any max limit. This is up to the customer,"
193-
" how ever high int they want to set")
194185
async def test_dispatcher_sync_threadpool_in_placeholder_above_max(self):
195-
"""Test if the sync threadpool will use the default setting when the
196-
app setting is above maximum
186+
"""Test if the sync threadpool will use the default max setting when
187+
the app setting is above maximum.
188+
189+
Note: This is designed for Linux Consumption.
197190
"""
198-
with patch('azure_functions_worker.dispatcher.logger') as mock_logger:
191+
with patch('azure_functions_worker.dispatcher.logger'):
199192
async with self._ctrl as host:
200193
await self._check_if_function_is_ok(host)
201194

@@ -204,13 +197,7 @@ async def test_dispatcher_sync_threadpool_in_placeholder_above_max(self):
204197
PYTHON_THREADPOOL_THREAD_COUNT: f'{self._over_max_workers}'
205198
})
206199
await self._assert_workers_threadpool(self._ctrl, host,
207-
self._default_workers)
208-
209-
mock_logger.warning.assert_any_call(
210-
f'{PYTHON_THREADPOOL_THREAD_COUNT} must be set to a '
211-
f'value '
212-
'between 1 and 1024. '
213-
'Reverting to default value for max_workers')
200+
self._allowed_max_workers)
214201

215202
async def test_dispatcher_sync_threadpool_in_placeholder_below_min(self):
216203
"""Test if the sync threadpool will use the default setting when the
@@ -229,10 +216,11 @@ async def test_dispatcher_sync_threadpool_in_placeholder_below_min(self):
229216
self._default_workers)
230217

231218
mock_logger.warning.assert_any_call(
232-
f'{PYTHON_THREADPOOL_THREAD_COUNT} must be set to a value '
233-
f'between {PYTHON_THREADPOOL_THREAD_COUNT_MIN} and '
234-
f'{PYTHON_THREADPOOL_THREAD_COUNT_MAX}. Reverting to '
235-
f'default value for max_workers')
219+
f'{PYTHON_THREADPOOL_THREAD_COUNT} must be set '
220+
f'to a value between '
221+
f'{PYTHON_THREADPOOL_THREAD_COUNT_MIN} and '
222+
'sys.maxint. Reverting to default value for '
223+
'max_workers')
236224

237225
async def test_sync_invocation_request_log(self):
238226
with patch('azure_functions_worker.dispatcher.logger') as mock_logger:
@@ -418,32 +406,52 @@ def setUp(self):
418406
self.mock_version_info = patch(
419407
'azure_functions_worker.dispatcher.sys.version_info',
420408
SysVersionInfo(3, 8, 0, 'final', 0))
409+
self._over_max_workers: int = 10000
410+
self._allowed_max_workers: int = self._over_max_workers
421411
self.mock_version_info.start()
422412

423413
def tearDown(self):
424414
os.environ.clear()
425415
os.environ.update(self._pre_env)
426416
self.mock_version_info.stop()
427417

418+
async def test_dispatcher_sync_threadpool_in_placeholder_above_max(self):
419+
"""Test if the sync threadpool will use any value and there isn't any
420+
artificial max value set.
421+
"""
422+
with patch('azure_functions_worker.dispatcher.logger'):
423+
async with self._ctrl as host:
424+
await self._check_if_function_is_ok(host)
425+
426+
# Reload environment variable on specialization
427+
await host.reload_environment(environment={
428+
PYTHON_THREADPOOL_THREAD_COUNT: f'{self._over_max_workers}'
429+
})
430+
await self._assert_workers_threadpool(self._ctrl, host,
431+
self._allowed_max_workers)
432+
self.assertNotEqual(
433+
self._ctrl._worker.get_sync_tp_workers_set(),
434+
self._default_workers)
435+
428436

429437
@unittest.skipIf(sys.version_info.minor != 9,
430438
"Run the tests only for Python 3.9. In other platforms, "
431439
"as the default passed is None, the cpu_count determines the "
432440
"number of max_workers and we cannot mock the os.cpu_count() "
433441
"in the concurrent.futures.ThreadPoolExecutor")
434-
class TestThreadPoolSettingsPython39(TestThreadPoolSettingsPython37):
442+
class TestThreadPoolSettingsPython39(TestThreadPoolSettingsPython38):
435443
def setUp(self):
436444
super(TestThreadPoolSettingsPython39, self).setUp()
437445

438446
self.mock_os_cpu = patch(
439447
'os.cpu_count', return_value=2)
440-
self.mock_os_cpu.start()
441448
# 6 - based on 2 cores - min(32, (os.cpu_count() or 1) + 4) - 2 + 4
442449
self._default_workers: Optional[int] = 6
443-
444450
self.mock_version_info = patch(
445451
'azure_functions_worker.dispatcher.sys.version_info',
446452
SysVersionInfo(3, 9, 0, 'final', 0))
453+
454+
self.mock_os_cpu.start()
447455
self.mock_version_info.start()
448456

449457
def tearDown(self):

0 commit comments

Comments
 (0)