blob: 8c6ef6331e57d14bc2eb4319d5d4e2f8296f6b2f [file] [edit]
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>User Guide &#8212; more-executors documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/alabaster.css" />
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script>
<script src="_static/doctools.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="Reference" href="api-reference.html" />
<link rel="prev" title="more-executors" href="index.html" />
<link rel="stylesheet" href="_static/custom.css" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />
</head><body>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="user-guide">
<h1>User Guide<a class="headerlink" href="#user-guide" title="Permalink to this headline"></a></h1>
<section id="base-executors">
<span id="id1"></span><h2>Base executors<a class="headerlink" href="#base-executors" title="Permalink to this headline"></a></h2>
<p>These methods on the <code class="xref py py-class docutils literal notranslate"><span class="pre">more_executors.Executors</span></code> class
create standalone <a class="reference external" href="https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.Executor" title="(in Python v3.11)"><code class="xref py py-class docutils literal notranslate"><span class="pre">Executor</span></code></a>
instances which may serve as the basis of <a class="reference internal" href="#composing-executors">composing executors</a>.</p>
<blockquote>
<div><dl class="simple">
<dt><a class="reference internal" href="reference/base-executors.html#more_executors.Executors.thread_pool" title="more_executors.Executors.thread_pool"><code class="xref py py-meth docutils literal notranslate"><span class="pre">thread_pool()</span></code></a></dt><dd><p>creates a new <a class="reference external" href="https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor" title="(in Python v3.11)"><code class="xref py py-class docutils literal notranslate"><span class="pre">ThreadPoolExecutor</span></code></a>
to execute callables in threads.</p>
</dd>
<dt><a class="reference internal" href="reference/base-executors.html#more_executors.Executors.process_pool" title="more_executors.Executors.process_pool"><code class="xref py py-meth docutils literal notranslate"><span class="pre">process_pool()</span></code></a></dt><dd><p>creates a new <a class="reference external" href="https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor" title="(in Python v3.11)"><code class="xref py py-class docutils literal notranslate"><span class="pre">ProcessPoolExecutor</span></code></a>
to execute callables in processes.</p>
</dd>
<dt><a class="reference internal" href="reference/base-executors.html#more_executors.Executors.sync" title="more_executors.Executors.sync"><code class="xref py py-meth docutils literal notranslate"><span class="pre">sync()</span></code></a></dt><dd><p>creates a new <a class="reference internal" href="reference/base-executors.html#more_executors.SyncExecutor" title="more_executors.SyncExecutor"><code class="xref py py-class docutils literal notranslate"><span class="pre">SyncExecutor</span></code></a>
to execute callables in the calling thread.</p>
</dd>
</dl>
</div></blockquote>
<p>Example:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">more_executors</span> <span class="kn">import</span> <span class="n">Executors</span>
<span class="k">with</span> <span class="n">Executors</span><span class="o">.</span><span class="n">thread_pool</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;web-client&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">executor</span><span class="p">:</span>
<span class="n">future</span> <span class="o">=</span> <span class="n">executor</span><span class="o">.</span><span class="n">submit</span><span class="p">(</span><span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">,</span> <span class="s1">&#39;https://github.com/rohanpm/more-executors&#39;</span><span class="p">)</span>
</pre></div>
</div>
</section>
<section id="composing-executors">
<span id="id2"></span><h2>Composing executors<a class="headerlink" href="#composing-executors" title="Permalink to this headline"></a></h2>
<p>Executors produced by this module can be customized by chaining a series of
<cite>with_*</cite> methods. This may be used to compose different behaviors for specific
use-cases.</p>
<p>Methods for composition are provided for all implemented executors:</p>
<blockquote>
<div><dl class="simple">
<dt><a class="reference internal" href="reference/futures-map.html#more_executors.Executors.with_map" title="more_executors.Executors.with_map"><code class="xref py py-meth docutils literal notranslate"><span class="pre">with_map()</span></code></a></dt><dd><p>transform the output of a future, synchronously</p>
</dd>
<dt><a class="reference internal" href="reference/futures-map.html#more_executors.Executors.with_flat_map" title="more_executors.Executors.with_flat_map"><code class="xref py py-meth docutils literal notranslate"><span class="pre">with_flat_map()</span></code></a></dt><dd><p>transform the output of a future, asynchronously</p>
</dd>
<dt><a class="reference internal" href="reference/retry.html#more_executors.Executors.with_retry" title="more_executors.Executors.with_retry"><code class="xref py py-meth docutils literal notranslate"><span class="pre">with_retry()</span></code></a></dt><dd><p>retry failing futures</p>
</dd>
<dt><a class="reference internal" href="reference/poll.html#more_executors.Executors.with_poll" title="more_executors.Executors.with_poll"><code class="xref py py-meth docutils literal notranslate"><span class="pre">with_poll()</span></code></a></dt><dd><p>resolve futures via a custom poll function</p>
</dd>
<dt><a class="reference internal" href="reference/timeout.html#more_executors.Executors.with_timeout" title="more_executors.Executors.with_timeout"><code class="xref py py-meth docutils literal notranslate"><span class="pre">with_timeout()</span></code></a></dt><dd><p>cancel unresolved futures after a timeout</p>
</dd>
<dt><a class="reference internal" href="reference/throttle.html#more_executors.Executors.with_throttle" title="more_executors.Executors.with_throttle"><code class="xref py py-meth docutils literal notranslate"><span class="pre">with_throttle()</span></code></a></dt><dd><p>limit the number of concurrently executing futures</p>
</dd>
<dt><a class="reference internal" href="reference/cancel.html#more_executors.Executors.with_cancel_on_shutdown" title="more_executors.Executors.with_cancel_on_shutdown"><code class="xref py py-meth docutils literal notranslate"><span class="pre">with_cancel_on_shutdown()</span></code></a></dt><dd><p>cancel any pending futures on executor shutdown</p>
</dd>
<dt><a class="reference internal" href="reference/asyncio.html#more_executors.Executors.with_asyncio" title="more_executors.Executors.with_asyncio"><code class="xref py py-meth docutils literal notranslate"><span class="pre">with_asyncio()</span></code></a></dt><dd><p>bridge between <a class="reference external" href="https://docs.python.org/3/library/concurrent.futures.html#module-concurrent.futures" title="(in Python v3.11)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">concurrent.futures</span></code></a> and <a class="reference external" href="https://docs.python.org/3/library/asyncio.html#module-asyncio" title="(in Python v3.11)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">asyncio</span></code></a></p>
</dd>
</dl>
</div></blockquote>
<p>Example:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># Run in up to 4 threads, retry on failure, transform output values</span>
<span class="n">executor</span> <span class="o">=</span> <span class="n">Executors</span><span class="o">.</span><span class="n">thread_pool</span><span class="p">(</span><span class="n">max_workers</span><span class="o">=</span><span class="mi">4</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s1">&#39;web-client&#39;</span><span class="p">)</span><span class="o">.</span> \
<span class="n">with_map</span><span class="p">(</span><span class="k">lambda</span> <span class="n">response</span><span class="p">:</span> <span class="n">response</span><span class="o">.</span><span class="n">json</span><span class="p">())</span><span class="o">.</span> \
<span class="n">with_retry</span><span class="p">()</span>
<span class="n">responses</span> <span class="o">=</span> <span class="p">[</span><span class="n">executor</span><span class="o">.</span><span class="n">submit</span><span class="p">(</span><span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">,</span> <span class="n">url</span><span class="p">)</span>
<span class="k">for</span> <span class="n">url</span> <span class="ow">in</span> <span class="n">urls</span><span class="p">]</span>
</pre></div>
</div>
<p>Keep in mind that the order in which executors are composed is significant.
For example, these two composition sequences have different effects:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">Executors</span><span class="o">.</span><span class="n">sync</span><span class="p">()</span><span class="o">.</span><span class="n">with_retry</span><span class="p">()</span><span class="o">.</span><span class="n">with_throttle</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
</pre></div>
</div>
<p>In this example, if 4 callables have failed and retries are currently pending,
throttling takes effect, and any additional callables will be enqueued until at
least one of the earlier callables has completed (or exhausted all retry
attempts).</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">Executors</span><span class="o">.</span><span class="n">sync</span><span class="p">()</span><span class="o">.</span><span class="n">with_throttle</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="o">.</span><span class="n">with_retry</span><span class="p">()</span>
</pre></div>
</div>
<p>In this example, an unlimited number of futures may be failed and awaiting
retries. The throttling in this example has no effect, since a
<a class="reference internal" href="reference/base-executors.html#more_executors.SyncExecutor" title="more_executors.SyncExecutor"><code class="xref py py-class docutils literal notranslate"><span class="pre">SyncExecutor</span></code></a> is intrinsically throttled to
a single pending future.</p>
</section>
<section id="naming-executors">
<span id="id3"></span><h2>Naming executors<a class="headerlink" href="#naming-executors" title="Permalink to this headline"></a></h2>
<p>All executors accept an optional <code class="docutils literal notranslate"><span class="pre">name</span></code> argument, an arbitrary string.
Setting the <code class="docutils literal notranslate"><span class="pre">name</span></code> when creating an executor has the following effects:</p>
<ul class="simple">
<li><p>If the executor creates any threads, the thread name will include the
specified value.</p></li>
<li><p>The name will be used as <code class="docutils literal notranslate"><span class="pre">executor</span></code> label on any <a class="reference internal" href="#metrics"><span class="std std-ref">Prometheus metrics</span></a>
associated with the executor.</p></li>
</ul>
<p>When creating chained executors via the <code class="docutils literal notranslate"><span class="pre">with_*</span></code> methods
(see <a class="reference internal" href="#composing-executors"><span class="std std-ref">Composing executors</span></a>), names automatically propagate through
the chain:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">Executors</span><span class="o">.</span><span class="n">thread_pool</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;svc-client&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">with_retry</span><span class="p">()</span><span class="o">.</span><span class="n">with_throttle</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
</pre></div>
</div>
<p>In the above example, three executors are created and all of them are
given the name <code class="docutils literal notranslate"><span class="pre">svc-client</span></code>.</p>
</section>
<section id="composing-futures">
<h2>Composing futures<a class="headerlink" href="#composing-futures" title="Permalink to this headline"></a></h2>
<p>A series of functions are provided for creating and composing
<code class="xref py py-class docutils literal notranslate"><span class="pre">Future</span></code> objects. These functions
may be used standalone, or in conjunction with the Executor
implementations in <code class="docutils literal notranslate"><span class="pre">more-executors</span></code>.</p>
<table class="docutils align-default">
<colgroup>
<col style="width: 29%" />
<col style="width: 46%" />
<col style="width: 25%" />
</colgroup>
<thead>
<tr class="row-odd"><th class="head"><p>Function</p></th>
<th class="head"><p>Signature</p></th>
<th class="head"><p>Description</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p><a class="reference internal" href="reference/futures-create.html#more_executors.f_return" title="more_executors.f_return"><code class="xref py py-meth docutils literal notranslate"><span class="pre">f_return()</span></code></a></p></td>
<td><dl class="simple">
<dt>X</dt><dd><p>⟶ Future&lt;X&gt;</p>
</dd>
</dl>
</td>
<td><p>wrap any value in a future</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="reference/futures-create.html#more_executors.f_return_error" title="more_executors.f_return_error"><code class="xref py py-meth docutils literal notranslate"><span class="pre">f_return_error()</span></code></a></p></td>
<td><p><cite>n/a</cite></p></td>
<td><p>wrap any exception in a future</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="reference/futures-create.html#more_executors.f_return_cancelled" title="more_executors.f_return_cancelled"><code class="xref py py-meth docutils literal notranslate"><span class="pre">f_return_cancelled()</span></code></a></p></td>
<td><p><cite>n/a</cite></p></td>
<td><p>get a cancelled future</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="reference/futures-apply.html#more_executors.f_apply" title="more_executors.f_apply"><code class="xref py py-meth docutils literal notranslate"><span class="pre">f_apply()</span></code></a></p></td>
<td><dl class="simple">
<dt>Future&lt;fn&lt;A[,B[,…]]⟶R&gt;&gt;, Future&lt;A&gt;[, Future&lt;B&gt;[, …]]</dt><dd><p>⟶ Future&lt;R&gt;</p>
</dd>
</dl>
</td>
<td><p>apply a function in the future</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="reference/futures-bool.html#more_executors.f_or" title="more_executors.f_or"><code class="xref py py-meth docutils literal notranslate"><span class="pre">f_or()</span></code></a></p></td>
<td><dl class="simple">
<dt>Future&lt;A&gt;[, Future&lt;B&gt;[, …]]</dt><dd><p>⟶ Future&lt;A|B|…&gt;</p>
</dd>
</dl>
</td>
<td><p>boolean <code class="docutils literal notranslate"><span class="pre">OR</span></code></p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="reference/futures-bool.html#more_executors.f_and" title="more_executors.f_and"><code class="xref py py-meth docutils literal notranslate"><span class="pre">f_and()</span></code></a></p></td>
<td><dl class="simple">
<dt>Future&lt;A&gt;[, Future&lt;B&gt;[, …]]</dt><dd><p>⟶ Future&lt;A|B|…&gt;</p>
</dd>
</dl>
</td>
<td><p>boolean <code class="docutils literal notranslate"><span class="pre">AND</span></code></p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="reference/futures-lists.html#more_executors.f_zip" title="more_executors.f_zip"><code class="xref py py-meth docutils literal notranslate"><span class="pre">f_zip()</span></code></a></p></td>
<td><dl class="simple">
<dt>Future&lt;A&gt;[, Future&lt;B&gt;[, …]]</dt><dd><p>⟶ Future&lt;A[, B[, …]]&gt;</p>
</dd>
</dl>
</td>
<td><p>combine futures into a tuple</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="reference/futures-map.html#more_executors.f_map" title="more_executors.f_map"><code class="xref py py-meth docutils literal notranslate"><span class="pre">f_map()</span></code></a></p></td>
<td><dl class="simple">
<dt>Future&lt;A&gt;, fn&lt;A⟶B&gt;</dt><dd><p>⟶ Future&lt;B&gt;</p>
</dd>
</dl>
</td>
<td><p>transform output value of a future
via a blocking function</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="reference/futures-map.html#more_executors.f_flat_map" title="more_executors.f_flat_map"><code class="xref py py-meth docutils literal notranslate"><span class="pre">f_flat_map()</span></code></a></p></td>
<td><dl class="simple">
<dt>Future&lt;A&gt;, fn&lt;A⟶Future&lt;B&gt;&gt;</dt><dd><p>⟶ Future&lt;B&gt;</p>
</dd>
</dl>
</td>
<td><p>transform output value of a future
via a non-blocking function</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="reference/futures-lists.html#more_executors.f_traverse" title="more_executors.f_traverse"><code class="xref py py-meth docutils literal notranslate"><span class="pre">f_traverse()</span></code></a></p></td>
<td><dl class="simple">
<dt>fn&lt;A⟶Future&lt;B&gt;&gt;, iterable&lt;A&gt;</dt><dd><p>⟶ Future&lt;list&lt;B&gt;&gt;</p>
</dd>
</dl>
</td>
<td><p>run non-blocking function over
iterable</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="reference/futures-lists.html#more_executors.f_sequence" title="more_executors.f_sequence"><code class="xref py py-meth docutils literal notranslate"><span class="pre">f_sequence()</span></code></a></p></td>
<td><dl class="simple">
<dt>list&lt;Future&lt;X&gt;&gt;</dt><dd><p>⟶ Future&lt;list&lt;X&gt;&gt;</p>
</dd>
</dl>
</td>
<td><p>convert list of futures to a future
of list</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="reference/cancel.html#more_executors.f_nocancel" title="more_executors.f_nocancel"><code class="xref py py-meth docutils literal notranslate"><span class="pre">f_nocancel()</span></code></a></p></td>
<td><dl class="simple">
<dt>Future&lt;X&gt;</dt><dd><p>⟶ Future&lt;X&gt;</p>
</dd>
</dl>
</td>
<td><p>make a future unable to be cancelled</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="reference/futures-proxy.html#more_executors.f_proxy" title="more_executors.f_proxy"><code class="xref py py-meth docutils literal notranslate"><span class="pre">f_proxy()</span></code></a></p></td>
<td><dl class="simple">
<dt>Future&lt;X&gt;</dt><dd><p>⟶ Future&lt;X&gt;</p>
</dd>
</dl>
</td>
<td><p>make a future proxy calls to the
future’s result</p></td>
</tr>
<tr class="row-odd"><td><p><a class="reference internal" href="reference/timeout.html#more_executors.f_timeout" title="more_executors.f_timeout"><code class="xref py py-meth docutils literal notranslate"><span class="pre">f_timeout()</span></code></a></p></td>
<td><dl class="simple">
<dt>Future&lt;X&gt;, float</dt><dd><p>⟶ Future&lt;X&gt;</p>
</dd>
</dl>
</td>
<td><p>make a future cancel itself after a
timeout has elapsed</p></td>
</tr>
</tbody>
</table>
</section>
<section id="usage-of-threads">
<h2>Usage of threads<a class="headerlink" href="#usage-of-threads" title="Permalink to this headline"></a></h2>
<p>Several executors internally make use of threads. Thus, executors should be
considered relatively heavyweight: creating dozens of executors within a
process is probably fine, creating thousands is possibly not.</p>
<p>Callbacks added by <a class="reference external" href="https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.Future.add_done_callback" title="(in Python v3.11)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">add_done_callback()</span></code></a> may
be invoked from any thread and should avoid any slow blocking operations.</p>
<p>All provided executors are thread-safe with the exception of the
<a class="reference external" href="https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.Executor.shutdown" title="(in Python v3.11)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">shutdown()</span></code></a> method, which should be called
from one thread only.</p>
</section>
<section id="executor-shutdown">
<h2>Executor shutdown<a class="headerlink" href="#executor-shutdown" title="Permalink to this headline"></a></h2>
<p>Shutting down an executor will also shut down all wrapped executors.</p>
<p>In the example below, any threads created by the
<a class="reference external" href="https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor" title="(in Python v3.11)"><code class="xref py py-class docutils literal notranslate"><span class="pre">ThreadPoolExecutor</span></code></a>, as well as the thread
created by the <a class="reference internal" href="reference/retry.html#more_executors.RetryExecutor" title="more_executors.RetryExecutor"><code class="xref py py-class docutils literal notranslate"><span class="pre">RetryExecutor</span></code></a>, will be joined
at the end of the <cite>with</cite> block:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">executor</span> <span class="o">=</span> <span class="n">Executors</span><span class="o">.</span><span class="n">thread_pool</span><span class="p">()</span><span class="o">.</span> \
<span class="n">with_map</span><span class="p">(</span><span class="n">check_result</span><span class="p">)</span><span class="o">.</span> \
<span class="n">with_retry</span><span class="p">()</span>
<span class="k">with</span> <span class="n">executor</span><span class="p">:</span>
<span class="n">do_something</span><span class="p">(</span><span class="n">executor</span><span class="p">)</span>
<span class="n">do_other_thing</span><span class="p">(</span><span class="n">executor</span><span class="p">)</span>
</pre></div>
</div>
<p>Note this implies that sharing of executors needs to be done carefully.
For example, this code is broken:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">executor</span> <span class="o">=</span> <span class="n">Executors</span><span class="o">.</span><span class="n">thread_pool</span><span class="p">()</span><span class="o">.</span><span class="n">with_map</span><span class="p">(</span><span class="n">check_result</span><span class="p">)</span>
<span class="c1"># Only need retries on this part</span>
<span class="k">with</span> <span class="n">executor</span><span class="o">.</span><span class="n">with_retry</span><span class="p">()</span> <span class="k">as</span> <span class="n">retry_executor</span><span class="p">:</span>
<span class="n">do_flaky_something</span><span class="p">(</span><span class="n">retry_executor</span><span class="p">)</span>
<span class="c1"># BUG: don&#39;t do this!</span>
<span class="c1"># The thread pool executor was already shut down, so this won&#39;t work.</span>
<span class="k">with</span> <span class="n">executor</span><span class="p">:</span>
<span class="n">do_something</span><span class="p">(</span><span class="n">executor</span><span class="p">)</span>
</pre></div>
</div>
<p>Generally, shutting down executors is optional and is not necessary to
(eventually) reclaim resources.</p>
<p>However, where executors accept caller-provided code (such as the polling
function to <a class="reference internal" href="reference/poll.html#more_executors.PollExecutor" title="more_executors.PollExecutor"><code class="xref py py-class docutils literal notranslate"><span class="pre">PollExecutor</span></code></a> or the retry
policy to <a class="reference internal" href="reference/retry.html#more_executors.RetryExecutor" title="more_executors.RetryExecutor"><code class="xref py py-class docutils literal notranslate"><span class="pre">RetryExecutor</span></code></a>), it is easy to
accidentally create a circular reference between the provided code and the
executor. When this happens, it will no longer be possible for the garbage
collector to clean up the executor’s resources automatically and a thread
leak may occur. If in doubt, call
<a class="reference external" href="https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.Executor.shutdown" title="(in Python v3.11)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">shutdown()</span></code></a>.</p>
</section>
<section id="prometheus-metrics">
<span id="metrics"></span><h2>Prometheus metrics<a class="headerlink" href="#prometheus-metrics" title="Permalink to this headline"></a></h2>
<p>This library automatically collects <a class="reference external" href="https://prometheus.io/">Prometheus</a>
metrics if the <code class="docutils literal notranslate"><span class="pre">prometheus_client</span></code> Python module is available.
The feature is disabled when this module is not installed or if the
<code class="docutils literal notranslate"><span class="pre">MORE_EXECUTORS_PROMETHEUS</span></code> environment variable is set to <code class="docutils literal notranslate"><span class="pre">0</span></code>.</p>
<p>If you want to ensure that <code class="docutils literal notranslate"><span class="pre">more-executors</span></code> is installed along with
all prometheus dependencies, you may request the ‘prometheus’ extras,
as in example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="n">more</span><span class="o">-</span><span class="n">executors</span><span class="p">[</span><span class="n">prometheus</span><span class="p">]</span>
</pre></div>
</div>
<p>The library only collects metrics; it does not expose them.
You must use <code class="docutils literal notranslate"><span class="pre">prometheus_client</span></code> to expose metrics in the most
appropriate manner when integrating this library with your tool or service.
Here is a simple example to dump metrics to a file:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">prometheus_client</span>
<span class="n">prometheus_client</span><span class="o">.</span><span class="n">write_to_textfile</span><span class="p">(</span><span class="s1">&#39;metrics.txt&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>The following metrics are available:</p>
<blockquote>
<div><dl>
<dt><code class="docutils literal notranslate"><span class="pre">more_executors_exec_inprogress</span></code></dt><dd><p>A <em>gauge</em> for the number of executors currently in use.</p>
<p>“In use” means an executor has been created and <code class="docutils literal notranslate"><span class="pre">shutdown()</span></code> not
yet called. Incorrect usage of <code class="docutils literal notranslate"><span class="pre">shutdown()</span></code> (e.g. calling more than
once) will lead to inaccurate data.</p>
</dd>
<dt><code class="docutils literal notranslate"><span class="pre">more_executors_exec_total</span></code></dt><dd><p>A <em>counter</em> for the total number of executors created.</p>
</dd>
<dt><code class="docutils literal notranslate"><span class="pre">more_executors_future_inprogress</span></code></dt><dd><p>A <em>gauge</em> for the number of futures currently in progress.</p>
<p>“In progress” means a future has been created and not yet reached
a terminal state.</p>
</dd>
<dt><code class="docutils literal notranslate"><span class="pre">more_executors_future_total</span></code></dt><dd><p>A <em>counter</em> for the total number of futures created.</p>
</dd>
<dt><code class="docutils literal notranslate"><span class="pre">more_executors_future_cancel_total</span></code></dt><dd><p>A <em>counter</em> for the total number of futures cancelled.</p>
</dd>
<dt><code class="docutils literal notranslate"><span class="pre">more_executors_future_error_total</span></code></dt><dd><p>A <em>counter</em> for the total number of futures resolved with an exception.</p>
</dd>
<dt><code class="docutils literal notranslate"><span class="pre">more_executors_future_time_total</span></code></dt><dd><p>A <em>counter</em> for the total execution time (in seconds) of futures.</p>
<p>The execution time of a future is the period between the
creation and resolution of a future.</p>
</dd>
<dt><code class="docutils literal notranslate"><span class="pre">more_executors_poll_total</span></code></dt><dd><p>A <em>counter</em> for the total number of times a <a class="reference internal" href="reference/poll.html#poll-function"><span class="std std-ref">Poll function</span></a> was
invoked.</p>
</dd>
<dt><code class="docutils literal notranslate"><span class="pre">more_executors_poll_error_total</span></code></dt><dd><p>A <em>counter</em> for the total number of times a <a class="reference internal" href="reference/poll.html#poll-function"><span class="std std-ref">Poll function</span></a>
raised an exception.</p>
</dd>
<dt><code class="docutils literal notranslate"><span class="pre">more_executors_poll_time_total</span></code></dt><dd><p>A <em>counter</em> for the total execution time (in seconds) of
<a class="reference internal" href="reference/poll.html#poll-function"><span class="std std-ref">Poll function</span></a> calls.</p>
</dd>
<dt><code class="docutils literal notranslate"><span class="pre">more_executors_retry_total</span></code></dt><dd><p>A <em>counter</em> for the total number of times a future was retried
by <a class="reference internal" href="reference/retry.html#more_executors.RetryExecutor" title="more_executors.RetryExecutor"><code class="xref py py-class docutils literal notranslate"><span class="pre">RetryExecutor</span></code></a>.</p>
</dd>
<dt><code class="docutils literal notranslate"><span class="pre">more_executors_retry_queue</span></code></dt><dd><p>A <em>gauge</em> for the current queue size of a
<a class="reference internal" href="reference/retry.html#more_executors.RetryExecutor" title="more_executors.RetryExecutor"><code class="xref py py-class docutils literal notranslate"><span class="pre">RetryExecutor</span></code></a> (i.e. the
number of futures currently waiting to retry).</p>
</dd>
<dt><code class="docutils literal notranslate"><span class="pre">more_executors_retry_delay_total</span></code></dt><dd><p>A <em>counter</em> for the total time (in seconds) spent waiting to
retry futures via <a class="reference internal" href="reference/retry.html#more_executors.RetryExecutor" title="more_executors.RetryExecutor"><code class="xref py py-class docutils literal notranslate"><span class="pre">RetryExecutor</span></code></a>.</p>
</dd>
<dt><code class="docutils literal notranslate"><span class="pre">more_executors_throttle_queue</span></code></dt><dd><p>A <em>gauge</em> for the current queue size of a
<a class="reference internal" href="reference/throttle.html#more_executors.ThrottleExecutor" title="more_executors.ThrottleExecutor"><code class="xref py py-class docutils literal notranslate"><span class="pre">ThrottleExecutor</span></code></a> (i.e. the number of futures
not yet able to start due to throttling).</p>
</dd>
<dt><code class="docutils literal notranslate"><span class="pre">more_executors_timeout_total</span></code></dt><dd><p>A <em>counter</em> for the total number of futures cancelled due to timeout
via <a class="reference internal" href="reference/timeout.html#more_executors.TimeoutExecutor" title="more_executors.TimeoutExecutor"><code class="xref py py-class docutils literal notranslate"><span class="pre">TimeoutExecutor</span></code></a> or
<a class="reference internal" href="reference/timeout.html#more_executors.f_timeout" title="more_executors.f_timeout"><code class="xref py py-func docutils literal notranslate"><span class="pre">f_timeout()</span></code></a>.</p>
<p>Only successfully cancelled futures are included.</p>
</dd>
<dt><code class="docutils literal notranslate"><span class="pre">more_executors_shutdown_cancel_total</span></code></dt><dd><p>A <em>counter</em> for the total number of futures cancelled due to executor
shutdown via <a class="reference internal" href="reference/cancel.html#more_executors.CancelOnShutdownExecutor" title="more_executors.CancelOnShutdownExecutor"><code class="xref py py-class docutils literal notranslate"><span class="pre">CancelOnShutdownExecutor</span></code></a>.</p>
<p>Only successfully cancelled futures are included.</p>
</dd>
</dl>
</div></blockquote>
<p>Metrics include the following labels:</p>
<blockquote>
<div><dl>
<dt><code class="docutils literal notranslate"><span class="pre">type</span></code></dt><dd><p>The type of executor or future in use; e.g. <code class="docutils literal notranslate"><span class="pre">map</span></code>, <code class="docutils literal notranslate"><span class="pre">retry</span></code>,
<code class="docutils literal notranslate"><span class="pre">poll</span></code>.</p>
</dd>
<dt><code class="docutils literal notranslate"><span class="pre">executor</span></code></dt><dd><p>Name of executor (see <a class="reference internal" href="#naming-executors"><span class="std std-ref">Naming executors</span></a>).</p>
<p>Executors created for internal use by this library are named
<code class="docutils literal notranslate"><span class="pre">internal</span></code>.</p>
</dd>
</dl>
</div></blockquote>
</section>
</section>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<h1 class="logo"><a href="index.html">more-executors</a></h1>
<p class="blurb">A library of composable Python executors and futures</p>
<h3>Navigation</h3>
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul class="current">
<li class="toctree-l1 current"><a class="current reference internal" href="#">User Guide</a><ul>
<li class="toctree-l2"><a class="reference internal" href="#base-executors">Base executors</a></li>
<li class="toctree-l2"><a class="reference internal" href="#composing-executors">Composing executors</a></li>
<li class="toctree-l2"><a class="reference internal" href="#naming-executors">Naming executors</a></li>
<li class="toctree-l2"><a class="reference internal" href="#composing-futures">Composing futures</a></li>
<li class="toctree-l2"><a class="reference internal" href="#usage-of-threads">Usage of threads</a></li>
<li class="toctree-l2"><a class="reference internal" href="#executor-shutdown">Executor shutdown</a></li>
<li class="toctree-l2"><a class="reference internal" href="#prometheus-metrics">Prometheus metrics</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="api-reference.html">Reference</a></li>
</ul>
<hr />
<ul>
<li class="toctree-l1"><a href="https://github.com/rohanpm/more-executors">Source</a></li>
<li class="toctree-l1"><a href="https://pypi.python.org/pypi/more-executors">PyPI</a></li>
</ul>
<div class="relations">
<h3>Related Topics</h3>
<ul>
<li><a href="index.html">Documentation overview</a><ul>
<li>Previous: <a href="index.html" title="previous chapter">more-executors</a></li>
<li>Next: <a href="api-reference.html" title="next chapter">Reference</a></li>
</ul></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&copy;2021, Rohan McGovern.
|
<a href="_sources/user-guide.rst.txt"
rel="nofollow">Page source</a>
</div>
<a href="https://github.com/rohanpm/more-executors" class="github">
<img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub" class="github"/>
</a>
</body>
</html>