Как издать эпос только в том случае, если другой эпик закончен?

1

У меня есть 2 лица: получатель платежа и транзакция. У меня есть payeeCreateEpic что фильтры при started испускает обычную цепочку finished/failed. То же самое transactionCreateEpic.

Для простоты предположим, что Получатель платежа имеет только UUID и Имя. Транзакция, однако, может иметь одну из 3-х возможностей: не привязана ни к одному получателю (полезная нагрузка имеет payee: null), присоединена к существующему получателю (в пользовательском интерфейсе у пользователя есть выпадающий список всех получателей, где он выбирает одного, полезная нагрузка, имеющая payee: payee-uuid) или присоединен к несуществующему получателю (в пользовательском интерфейсе у пользователя есть возможность создать получателя, который не сохраняется в бэкэнде, но должен быть сохранен, если вся транзакция сохраняется, в полезной нагрузке, которую я отправляю payee: payee-name),

Теперь, если создать сделки представляется, не получателем платежа или существующего получателя платежа, я просто иду в POST/transactions и ждать его, чтобы решить, чтобы испускать finished или failed действие transactionCreateEpic.

Однако, если !isUuid(txPayload.payee) оценивается как true, в эпопее transactionCreateEpic payeeCreateEpic я хочу инициировать payeeCreateEpic с именем получателя платежа и ждать finished =>, а затем создать транзакцию с идентификатором получателя из серверной части или произошел failed => прервать транзакцию (и показать ошибку для пользователя).

Я не уверен, как это сделать, поскольку в эпосе транзакции я уже нахожусь внутри фильтра для действия TRANSACTION_CREATE_STARTED и не уверен, как я могу подписаться на другое действие, созданное payeeCreateEpic.

Некоторый код:

const createPayeeEpic = (actions$: Observable<Action>) =>
    actions$.pipe(
        filter(CreateAction.start.match),
        mergeMap((action) =>
            from(MoneyPinApiClient.getInstance().payee.create(CreateRequestAdapter(action.payload))).pipe(
                map((response) => CreateAction.success({
                    params: action.payload,
                    result: CreateResultAdapter(response.data)
                })),
                catchError((err) => of(
                    <any>CreateAction.failure({params: action.payload, error: err}),
                    <any>MoneyPinApiErrorAction(err)
                ))
            )
        )
    );
const createTransactionEpic = (actions$: Observable<Action>) =>
    actions$.pipe(
        filter(CreateAction.start.match),
        mergeMap((action) => {
            if(!isUuid(action.payload.payee) {
               **EMIT PayeeCreateAction.start({name: action.payload.payee})**
               **WAIT FOR PayeeCreateAction.success (or PayeeCreateAction.failure)**
               action.payload.payee = resultOf(PayeeCreateAction.success).id;
            }
            return from(MoneyPinApiClient.getInstance().transaction.create(CreateRequestAdapter(action.payload))).pipe(
                map((response) => CreateAction.success({
                        params: action.payload,
                        result: CreateResultAdapter(response.data)
                    })),
                catchError((err) => of(
                    <any>CreateAction.failure({params: action.payload, error: err}),
                    <any>MoneyPinApiErrorAction(err)
                ))
            )
        })
    );

Посмотрите на createTransactionEpic, вот где я с трудом могу инициировать createPayeeEpic + ожидание успешного сбоя.

  • 0
    Можете ли вы привести пример того, что вы пытаетесь сделать (в идеале на StackBlitz)?
  • 0
    @martin Отредактировал вопрос с примером кода
Показать ещё 2 комментария
Теги:
rxjs
redux
redux-observable

2 ответа

0
Лучший ответ

Решение состоит в том, чтобы извлечь фактическое создание транзакции в некоторый фабричный метод:

const transactionCreateStreamFactory = (action: MoneyPinAction<CreateActionParams>) =>
from(MoneyPinApiClient.getInstance().transaction.create(CreateRequestAdapter(action.payload))).pipe(
    concatMap((response) => CreateAction.success({
        params: action.payload,
        result: CreateResultAdapter(response.data)
    })),
    catchError((err) => of(
        <any>CreateAction.failure({params: action.payload, error: err}),
        <any>MoneyPinApiErrorAction(err)
    ))
);

И тогда эпопея создания транзакции на самом деле выглядит так:

const createTransactionEpic = (actions$: Observable<Action>) =>
actions$.pipe(
    filter(CreateAction.start.match),
    mergeMap((action) => {
        const {payee, payload} = action.payload;
        if (payee && payload.payee_id) {
            return merge(
                actions$.pipe(
                    filter(PayeeCreateAction.success.match),
                    filter((payeeResponse) => payeeResponse.payload.result.payee.id === payload.payee_id),
                    take(1),
                    mergeMap(() => transactionCreateStreamFactory(action)),
                ),
                actions$.pipe(
                    filter(PayeeCreateAction.failure.match),
                    filter((payeeResponse) => payeeResponse.payload.params.payload.id === payload.payee_id),
                    take(1),
                    map(() => CreateAction.failure({
                        params: action.payload,
                        error: new Error("failed to create payee")
                    }))
                )
            ).pipe(
                startWith(PayeeCreateAction.start({
                    notebook_id: action.payload.notebook_id,
                    payload: {id: payload.payee_id, name: payee}
                }))
            );
        } else {
            return transactionCreateStreamFactory(action);
        }
    })
);

Поэтому, если получатель платежа с идентификатором был задан во время создания, я бы запустил другой канал, который прослушивает действие payee.success или payee.failure, фильтрует соответствующее действие (в случае, если во время одновременного создания может произойти несколько действий этого типа или что-то еще), прослушивает только один раз (take(1)) и объединяет это с фактическим эпосом создания транзакции, и весь поток начинается с действия payee.start, которое обрабатывается эпосом получателя (и, в свою payee.start, вызывает успех/неудачу действия получателя).

0

Ваша проблема выглядит как синхронизация потоков. Используйте один из шаблонов синхронизации потоков. Например, https://en.wikipedia.org/wiki/Monitor_(synchronization)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню