An executor interface for :py:mod:`concurrent.futures` designed for working with Flask applications. :param app: A Flask application instance. :param name: An optional name for the executor. This can be used to configure multiple executors. Named executors will look for
| 57 | |
| 58 | |
| 59 | class Executor(InstanceProxy, concurrent.futures._base.Executor): |
| 60 | """An executor interface for :py:mod:`concurrent.futures` designed for |
| 61 | working with Flask applications. |
| 62 | |
| 63 | :param app: A Flask application instance. |
| 64 | :param name: An optional name for the executor. This can be used to |
| 65 | configure multiple executors. Named executors will look for |
| 66 | environment variables prefixed with the name in uppercase, |
| 67 | e.g. ``CUSTOM_EXECUTOR_TYPE``. |
| 68 | """ |
| 69 | |
| 70 | def __init__(self, app=None, name=''): |
| 71 | self.app = app |
| 72 | self._default_done_callbacks = [] |
| 73 | self.futures = FutureCollection() |
| 74 | if re.match(r'^(\w+)?$', name) is None: |
| 75 | raise ValueError( |
| 76 | "Executor names may only contain letters, numbers or underscores" |
| 77 | ) |
| 78 | self.name = name |
| 79 | if len(name) > 0: |
| 80 | name = name.upper() + '_' |
| 81 | self.EXECUTOR_TYPE = name + 'EXECUTOR_TYPE' |
| 82 | self.EXECUTOR_MAX_WORKERS = name + 'EXECUTOR_MAX_WORKERS' |
| 83 | self.EXECUTOR_FUTURES_MAX_LENGTH = name + 'EXECUTOR_FUTURES_MAX_LENGTH' |
| 84 | self.EXECUTOR_PROPAGATE_EXCEPTIONS = name + 'EXECUTOR_PROPAGATE_EXCEPTIONS' |
| 85 | if app is not None: |
| 86 | self.init_app(app) |
| 87 | |
| 88 | def init_app(self, app): |
| 89 | """Initialise application. This will also intialise the configured |
| 90 | executor type: |
| 91 | |
| 92 | * :class:`concurrent.futures.ThreadPoolExecutor` |
| 93 | * :class:`concurrent.futures.ProcessPoolExecutor` |
| 94 | """ |
| 95 | app.config.setdefault(self.EXECUTOR_TYPE, 'thread') |
| 96 | executor_type = app.config[self.EXECUTOR_TYPE] |
| 97 | executor_max_workers = default_workers(executor_type) |
| 98 | app.config.setdefault(self.EXECUTOR_MAX_WORKERS, executor_max_workers) |
| 99 | futures_max_length = app.config.setdefault(self.EXECUTOR_FUTURES_MAX_LENGTH, None) |
| 100 | propagate_exceptions = app.config.setdefault(self.EXECUTOR_PROPAGATE_EXCEPTIONS, False) |
| 101 | if futures_max_length is not None: |
| 102 | self.futures.max_length = int(futures_max_length) |
| 103 | if str2bool(propagate_exceptions): |
| 104 | self.add_default_done_callback(propagate_exceptions_callback) |
| 105 | self._self = self._make_executor(app) |
| 106 | app.extensions[self.name + 'executor'] = self |
| 107 | |
| 108 | def _make_executor(self, app): |
| 109 | executor_type = app.config[self.EXECUTOR_TYPE] |
| 110 | executor_max_workers = app.config[self.EXECUTOR_MAX_WORKERS] |
| 111 | if executor_max_workers is not None: |
| 112 | executor_max_workers = int(executor_max_workers) |
| 113 | if executor_type == 'thread': |
| 114 | _executor = concurrent.futures.ThreadPoolExecutor |
| 115 | elif executor_type == 'process': |
| 116 | _executor = concurrent.futures.ProcessPoolExecutor |
no outgoing calls