16
16
import threading
17
17
from asyncio import BaseEventLoop
18
18
from logging import LogRecord
19
- from typing import Optional , List
19
+ from typing import List , Optional
20
20
21
21
import grpc
22
22
@@ -75,11 +75,13 @@ def __init__(self, loop: BaseEventLoop, host: str, port: int,
75
75
76
76
self ._old_task_factory = None
77
77
78
- # We allow the customer to change synchronous thread pool count by
79
- # PYTHON_THREADPOOL_THREAD_COUNT app setting. The default value is 1.
80
- self ._sync_tp_max_workers : int = self ._get_sync_tp_max_workers ()
78
+ # We allow the customer to change synchronous thread pool max worker
79
+ # count by setting the PYTHON_THREADPOOL_THREAD_COUNT app setting.
80
+ # For 3.[6|7|8] The default value is 1.
81
+ # For 3.9, we don't set this value by default but we honor incoming
82
+ # the app setting.
81
83
self ._sync_call_tp : concurrent .futures .Executor = (
82
- self ._create_sync_call_tp (self ._sync_tp_max_workers )
84
+ self ._create_sync_call_tp (self ._get_sync_tp_max_workers () )
83
85
)
84
86
85
87
self ._grpc_connect_timeout : float = grpc_connect_timeout
@@ -90,6 +92,15 @@ def __init__(self, loop: BaseEventLoop, host: str, port: int,
90
92
self ._grpc_thread : threading .Thread = threading .Thread (
91
93
name = 'grpc-thread' , target = self .__poll_grpc )
92
94
95
+ def get_sync_tp_workers_set (self ):
96
+ """We don't know the exact value of the threadcount set for the Python
97
+ 3.9 scenarios (as we'll start passing only None by default), and we
98
+ need to get that information.
99
+
100
+ Ref: concurrent.futures.thread.ThreadPoolExecutor.__init__._max_workers
101
+ """
102
+ return self ._sync_call_tp ._max_workers
103
+
93
104
@classmethod
94
105
async def connect (cls , host : str , port : int , worker_id : str ,
95
106
request_id : str , connect_timeout : float ):
@@ -325,7 +336,8 @@ async def _handle__invocation_request(self, req):
325
336
]
326
337
if not fi .is_async :
327
338
function_invocation_logs .append (
328
- f'sync threadpool max workers: { self ._sync_tp_max_workers } '
339
+ f'sync threadpool max workers: '
340
+ f'{ self .get_sync_tp_workers_set ()} '
329
341
)
330
342
logger .info (', ' .join (function_invocation_logs ))
331
343
@@ -434,9 +446,8 @@ async def _handle__function_environment_reload_request(self, req):
434
446
435
447
# Apply PYTHON_THREADPOOL_THREAD_COUNT
436
448
self ._stop_sync_call_tp ()
437
- self ._sync_tp_max_workers = self ._get_sync_tp_max_workers ()
438
449
self ._sync_call_tp = (
439
- self ._create_sync_call_tp (self ._sync_tp_max_workers )
450
+ self ._create_sync_call_tp (self ._get_sync_tp_max_workers () )
440
451
)
441
452
442
453
# Reload package namespaces for customer's libraries
@@ -501,7 +512,8 @@ def _stop_sync_call_tp(self):
501
512
self ._sync_call_tp .shutdown ()
502
513
self ._sync_call_tp = None
503
514
504
- def _get_sync_tp_max_workers (self ) -> int :
515
+ @staticmethod
516
+ def _get_sync_tp_max_workers () -> Optional [int ]:
505
517
def tp_max_workers_validator (value : str ) -> bool :
506
518
try :
507
519
int_value = int (value )
@@ -511,20 +523,27 @@ def tp_max_workers_validator(value: str) -> bool:
511
523
return False
512
524
513
525
if int_value < PYTHON_THREADPOOL_THREAD_COUNT_MIN or (
514
- int_value > PYTHON_THREADPOOL_THREAD_COUNT_MAX ):
526
+ int_value > PYTHON_THREADPOOL_THREAD_COUNT_MAX ):
515
527
logger .warning (f'{ PYTHON_THREADPOOL_THREAD_COUNT } must be set '
516
- 'to a value between 1 and 32' )
528
+ 'to a value between 1 and 32. '
529
+ 'Reverting to default value for max_workers' )
517
530
return False
518
531
519
532
return True
520
533
521
- return int (get_app_setting (
522
- setting = PYTHON_THREADPOOL_THREAD_COUNT ,
523
- default_value = f'{ PYTHON_THREADPOOL_THREAD_COUNT_DEFAULT } ' ,
524
- validator = tp_max_workers_validator ))
534
+ # Starting Python 3.9, worker won't be putting a limit on the
535
+ # max_workers count in the created threadpool.
536
+ default_value = None if sys .version_info .minor == 9 \
537
+ else f'{ PYTHON_THREADPOOL_THREAD_COUNT_DEFAULT } '
538
+ max_workers = get_app_setting (setting = PYTHON_THREADPOOL_THREAD_COUNT ,
539
+ default_value = default_value ,
540
+ validator = tp_max_workers_validator )
541
+
542
+ # We can box the app setting as int for earlier python versions.
543
+ return int (max_workers ) if max_workers else None
525
544
526
545
def _create_sync_call_tp (
527
- self , max_worker : int ) -> concurrent .futures .Executor :
546
+ self , max_worker : Optional [ int ] ) -> concurrent .futures .Executor :
528
547
"""Create a thread pool executor with max_worker. This is a wrapper
529
548
over ThreadPoolExecutor constructor. Consider calling this method after
530
549
_stop_sync_call_tp() to ensure only 1 synchronous thread pool is
0 commit comments