1
0
mirror of https://github.com/twirl/The-API-Book.git synced 2025-08-10 21:51:42 +02:00

switched to async locks

This commit is contained in:
Sergey Konstantinov
2023-09-22 09:42:12 +03:00
parent a067bf28d4
commit 9e534d3a47
8 changed files with 15 additions and 15 deletions

Binary file not shown.

View File

@@ -6639,7 +6639,7 @@ api.<span class="hljs-title function_">subscribe</span>(
</ul>
<p>If you have read the previous chapters thoroughly, the solution to these problems should be obvious. We need to abstract from the fact of loading data and reformulate the issue in high-level terms. We have a shared resource: the space on the screen. Only one offer can be displayed at a time. This means that every actor needing lasting access to the panel must explicitly obtain it. This entails two conclusions:</p>
<ul>
<li>The access flag must have an explicit name, such as <code>offerFullViewLocked</code>m and not <code>isDataLoading</code>.</li>
<li>The access flag must have an explicit name, such as <code>offerFullViewLocked</code>, and not <code>isDataLoading</code>.</li>
<li><code>Composer</code> must control this flag, not the offer panel itself (additionally, because preparing data for displaying in the panel is <code>Composer</code>'s responsibility).</li>
</ul>
<pre><code class="language-typescript"><span class="hljs-keyword">class</span> <span class="hljs-title class_">SearchBoxComposer</span> {
@@ -6669,9 +6669,9 @@ api.<span class="hljs-title function_">subscribe</span>(
selectOffer (offer) {
<span class="hljs-keyword">let</span> lock;
<span class="hljs-keyword">try</span> {
<span class="hljs-comment">// Trying to catpture the</span>
<span class="hljs-comment">// Trying to capture the</span>
<span class="hljs-comment">// `offerFullView` resource</span>
lock = <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">acquireLock</span>(
lock = <span class="hljs-keyword">await</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">acquireLock</span>(
<span class="hljs-string">'offerFullView'</span>, <span class="hljs-string">'10s'</span>
);
<span class="hljs-keyword">let</span> fullData = <span class="hljs-keyword">await</span> api
@@ -6696,7 +6696,7 @@ api.<span class="hljs-title function_">subscribe</span>(
</code></pre>
<p><strong>NB</strong>: the second argument to the <code>acquireLock</code> function is the lock's lifespan (10 seconds, in our case). This implies that the lock will be automatically released after this timeout has passed (which is useful in case we have forgotten to catch an exception or set a timeout for a data load request), thus unblocking the UI.</p>
<p>With this approach, we can implement not only locks, but also various scenarios to flexibly manage them. Let's add data regarding the acquirer in the lock function:</p>
<pre><code class="language-typescript">lock = <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">acquireLock</span>(
<pre><code class="language-typescript">lock = <span class="hljs-keyword">await</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">acquireLock</span>(
<span class="hljs-string">'offerFullView'</span>, <span class="hljs-string">'10s'</span>, {
<span class="hljs-comment">// Who is trying to acquire a lock</span>
<span class="hljs-comment">// and for what reason</span>
@@ -6714,12 +6714,12 @@ api.<span class="hljs-title function_">subscribe</span>(
<span class="hljs-comment">// of the lock</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}
})
});
</code></pre>
<p>Additionally, we might add a handler to react to losing control — for example, to cancel the request for data if it is no longer needed:</p>
<pre><code class="language-typescript">lock.<span class="hljs-property">events</span>.<span class="hljs-title function_">on</span>(<span class="hljs-string">'lost'</span>, <span class="hljs-function">() =></span> {
<span class="hljs-variable language_">this</span>.<span class="hljs-title function_">cancelFullOfferDataLoad</span>();
})
});
</code></pre>
<p>The shared resource access control partner aligns well with the “model” pattern: actors can acquire read and/or write locks for specific data fields (or groups of fields) of the model.</p>
<p><strong>NB</strong>: we could have addressed the data load problem differently:</p>

Binary file not shown.

Binary file not shown.

View File

@@ -6699,7 +6699,7 @@ api.<span class="hljs-title function_">subscribe</span>(
<span class="hljs-keyword">try</span> {
<span class="hljs-comment">// Пытаемся захватить ресурс</span>
<span class="hljs-comment">// `offerFullView`</span>
lock = <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">acquireLock</span>(
lock = <span class="hljs-keyword">await</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">acquireLock</span>(
<span class="hljs-string">'offerFullView'</span>, <span class="hljs-string">'10s'</span>
);
<span class="hljs-keyword">let</span> fullData = <span class="hljs-keyword">await</span> api
@@ -6724,7 +6724,7 @@ api.<span class="hljs-title function_">subscribe</span>(
</code></pre>
<p><strong>NB</strong>: вторым параметром в <code>acquireLock</code> мы передали максимальное время жизни блокировки — 10 секунд. Если в течение этого времени блокировка не снята (например, в случае, если мы забыли обработать какое-то исключение или выставить таймаут на запрос к серверу), она будет отменена автоматически, и интерфейс будет разблокирован.</p>
<p>В таком подходе мы можем реализовать не только блокировки, но и различные сценарии, которые позволяют нам более гибко ими управлять. Добавим в функцию захвата ресурса дополнительные данные о целях захвата:</p>
<pre><code class="language-typescript">lock = <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">acquireLock</span>(
<pre><code class="language-typescript">lock = <span class="hljs-keyword">await</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">acquireLock</span>(
<span class="hljs-string">'offerFullView'</span>, <span class="hljs-string">'10s'</span>, {
<span class="hljs-comment">// Добавляем описание,</span>
<span class="hljs-comment">// кто и зачем пытается</span>
@@ -6742,12 +6742,12 @@ api.<span class="hljs-title function_">subscribe</span>(
<span class="hljs-comment">// Иначе запрещаем перехват</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}
})
});
</code></pre>
<p>Дополнительно мы можем ввести и обработку потери контроля ресурса — например, отменить загрузку данных, которые больше не нужны.</p>
<pre><code class="language-typescript">lock.<span class="hljs-property">events</span>.<span class="hljs-title function_">on</span>(<span class="hljs-string">'lost'</span>, <span class="hljs-function">() =></span> {
<span class="hljs-variable language_">this</span>.<span class="hljs-title function_">cancelFullOfferDataLoad</span>();
})
});
</code></pre>
<p>Паттерн контроля разделяемых ресурсов также хорошо сочетается с паттерном «модель»: акторы могут захватывать доступ на чтение и/или изменение свойств или групп свойств модели.</p>
<p><strong>NB</strong>: мы могли бы решить проблему подгрузки данных иначе:</p>

Binary file not shown.

View File

@@ -97,9 +97,9 @@ class SearchBoxComposer {
selectOffer (offer) {
let lock;
try {
// Trying to catpture the
// Trying to capture the
// `offerFullView` resource
lock = this.acquireLock(
lock = await this.acquireLock(
'offerFullView', '10s'
);
let fullData = await api
@@ -128,7 +128,7 @@ class SearchBoxComposer {
With this approach, we can implement not only locks, but also various scenarios to flexibly manage them. Let's add data regarding the acquirer in the lock function:
```typescript
lock = this.acquireLock(
lock = await this.acquireLock(
'offerFullView', '10s', {
// Who is trying to acquire a lock
// and for what reason

View File

@@ -99,7 +99,7 @@ class SearchBoxComposer {
try {
// Пытаемся захватить ресурс
// `offerFullView`
lock = this.acquireLock(
lock = await this.acquireLock(
'offerFullView', '10s'
);
let fullData = await api
@@ -128,7 +128,7 @@ class SearchBoxComposer {
В таком подходе мы можем реализовать не только блокировки, но и различные сценарии, которые позволяют нам более гибко ими управлять. Добавим в функцию захвата ресурса дополнительные данные о целях захвата:
```typescript
lock = this.acquireLock(
lock = await this.acquireLock(
'offerFullView', '10s', {
// Добавляем описание,
// кто и зачем пытается