Introduction of concurrency
This ADR is effective starting from v0.12.
TL;DR
To apply concurrency settings to the Query or Mutation use concurrency
operator:
import { concurrency } from '@farfetched/core';
concurrency(operation, { strategy: 'TAKE_LATEST' });
To abort all in-flight requests use abortAll
Event:
import { createEvent } from 'effector';
import { concurrency } from '@farfetched/core';
const abortAll = createEvent();
concurrency(operation, { abortAll });
By default, no concurrency settings are applied.
Field concurrency
in factories createJsonQuery
and createJsonMutation
will be deleted.
Configuration vs. Operators
This change is about global movement of Farfetched's API from configuration to operators. Configuration of operation during its creation has a couple of drawbacks:
It makes creation of custom factories in user-land harder, because they have to support all possible configurations and their combinations. On the other hand, operators are easier to support because they are just functions that can be called with any operation.
It makes code-generation harder, because it requires to generate the whole configuration object in generated code and user does not have a chance to modify it. On the other hand, operators can be called in separate file and its calls would not be affected by code-generation.
The last but not least, operator is more Effector-ish way of doing things, because any operator is just a set of sample
-s which is foundation of Effector.
For example, let us take a look at the following code:
retry(query, {
times: 12,
});
Basically, it can be rewritten as:
const nextRetry = createEvent();
const $retriesNotExceededLimit = createStore(false);
sample({
clock: query.finished.failed,
filter: $retriesNotExceededLimit,
target: [query.start, nextRetry],
});
sample({
clock: nextRetry,
source: $retryNumber,
fn: (retryNumber) => retryNumber <= 12,
target: $retriesNotExceededLimit,
});
TIP
It is not a real implementation of retry
operator, but it is a good example of how it can be implemented using Effector primitives.
So, Farfetched's API is moving from configuration to operators (retry
, cache
, timeout
, etc.), and this ADR is about moving concurrency
settings to operator as well.
Future of concurrency
Historical context
Historically, concurrency settings were applied directly to the Query or Mutation using createJsonQuery
and createJsonMutation
factories and concurrency
field:
import { createJsonQuery } from '@farfetched/core';
const query = createJsonQuery({
concurrency: { strategy: 'TAKE_FIRST' },
});
Furthermore, concurrency.strategy
has a default value TAKE_LATEST
which means that by default, all in-flight requests are aborted except the latest one. But only Queries created by createJsonQuery
had this default, any other operations had TAKE_EVERY
as a default.
This behavior is considered harmful and after introducing the concurrency
operator, default concurrency strategy is switched to TAKE_EVERY
for all use-case which means that all in-flight requests are executed concurrently.
Configuration to operator
Field concurrency
in createJsonQuery
and createJsonMutation
is deprecated. Instead, use concurrency
operator.
strategy
is mapped as is:
import { createJsonQuery, concurrency } from '@farfetched/core';
const query = createJsonQuery({
concurrency: { strategy: 'TAKE_LATEST' },
});
concurrency(query, { strategy: 'TAKE_LATEST' });
abort
is renamed to abortAll
:
import { createJsonQuery, concurrency } from '@farfetched/core';
import { createEvent } from 'effector';
const abortQuery = createEvent();
const query = createJsonQuery({
concurrency: { abort: abortQuery },
});
concurrency(query, { abortAll: abortQuery });
Furthermore, default concurrency strategy is switched to TAKE_EVERY
. Before, the default strategy was TAKE_LATEST
in createJsonQuery
. Now, all operations have TAKE_EVERY
as a default which means that all in-flight requests are executed concurrently.
Changes schedule
Since this change requires a change in the user code, it is scheduled for the couple of releases:
v0.12
- Operator
concurrency
is introduced. It can be used to apply concurrency settings to any Queries or Mutations. concurrency
field increateJsonQuery
andcreateJsonMutation
is deprecated.- In case of usage operator
concurrency
withcreateJsonQuery
withoutconcurrency
field, everything is fine. No deprecation message is written. - In case of usage operator
concurrency
withcreateJsonQuery
withconcurrency
field, deprecation message is written withconsole.warning
.
v0.13
createJsonQuery
requires applyingconcurrency
operator on then to specify concurrency settings. Otherwise, a deprecation message is written withconsole.warning
. The reason for this is to make sure that the user is aware of the change of default behavior.
v0.14
concurrency
field increateJsonQuery
andcreateJsonMutation
is removed. Default strategy isTAKE_EVERY
for any Mutation or any Query.