Самовосстанавливающийся круговой поток в wolkenkit

У меня есть вопрос о потоках с состоянием, я попытаюсь разбить его на очень простой пример: я использую разные состояния, скажем, нетронутые, добавляющие и вычисляющие. Мое состояние состоит из int, к которому я хочу добавить, и после того, как я добавил к нему дважды, я хочу вычислить удвоенную сумму, а затем снова установить ее в исходное состояние. Итак, теперь я начну с исходного потока, int = 0. Внутри моих переходов я реагирую на событие addNumber, беру целое число из данных события и добавляю его к своему состоянию, затем я transitionTo('add'). Я повторяю это, добавляю еще одну цифру и transitionTo('calculate'). В своих реакциях я теперь реагирую на переход между добавлением и вычислением и устанавливаю новое состояние, чтобы удвоить количество int. Что я хочу сделать сейчас, так это поработать с этим номером, например, отправить команду, содержащую его, а затем сбросить состояние и transitionTo('pristine'). Проблема в том, что я не могу установить состояние и не могу перейти. Как вы справляетесь с этим?

Здесь у вас есть фактический код, чтобы он стал немного более понятным:

'use strict';

const identity = {
        'usermgmt.user.presentSwitched': event => event.user.id,
    'usermgmt.user.pauseSwitched': event => event.user.id
};

const initialState = {
    is: 'pristine',
    present: false,
    pause: false,
    presentSince: null,
    presentUntil: null,
    pauses: [],
};

const transitions = {
    pristine: {
        'usermgmt.user.presentSwitched' (flow, event) {
            flow.setState({
                present: true,
                presentSince: event.data.timestamp
            });
            flow.transitionTo('present');
        }
    },
    present: {
        'usermgmt.user.presentSwitched' (flow, event) {
            flow.setState({
                present: false,
                presentUntil: event.data.timestamp
            });
            flow.transitionTo('calculating');
        },
        'usermgmt.user.pauseSwitched' (flow, event) {
            const newPause = {pauseSince: event.data.timestamp};
            flow.setState({
                pause: true,
                pauses: [...flow.state.pauses, newPause]
        });
            flow.transitionTo('pause');
        }
    },
    pause: {
        'usermgmt.user.pauseSwitched' (flow, event) {
            const pauses = Object.create(flow.state.pauses);
            pauses[flow.state.pauses.length - 1].pauseUntil = event.data.timestamp;
            flow.setState({
                pause: false,
                pauseSince: event.data.timestamp,
                pauses
            });
            flow.transitionTo('present');
        }
    }
};

const reactions = {
    present: {
        'calculating' (flow, event, services) {
            const {app, logger} = services;

            const workDayId = 'kek';
            const from = flow.state.presentSince;
            const to = flow.state.presentUntil;
            const pauses = flow.state.pauses;

            logger.info(JSON.stringify(flow));

            app.keksing.recording().createRecording({workDayId, from, to, type: 'working'});

            flow.setState({
                present: false,
                pause: false,
                presentSince: null,
                presentUntil: null,
                pauses: [],
            });
            flow.transitionTo('pristine');
        }
    }
};

module.exports = { identity, initialState, transitions, reactions };

https://gist.github.com/DrFelder/122a72ffed3eb239a1a3ae33c99ea00d


person Thomas Pötzsch    schedule 23.08.2018    source источник


Ответы (1)


В общем, есть две мысли по этому поводу:

  1. Первый вариант — задаться вопросом, следует ли вам вообще использовать здесь поток. Возможно, вы могли бы смоделировать это как агрегат с такими командами, как startWork, endWork, pause и resume, с желаемым состоянием, и тогда вы могли бы иметь логику, которую вы хотите иметь внутри этого агрегата. Вы можете использовать либо один агрегат на человека, либо один агрегат на блок присутствия. В любом случае, это должно сработать. Итак, выражаясь другими словами: есть ли особая причина, по которой вы хотите реализовать это как поток, а не как совокупность?
  2. Второй вариант - не различать pristine и calculating. Потому что то, что вы действительно хотите иметь, — это некий круг, но ваш поток не моделируется как круг. Таким образом, если вместо окончательного перехода к calculating вы перейдете обратно к pristine, вы окажетесь в желаемом состоянии, и внутри реакции present->pristine вы сможете выполнить расчет, который хотите, и отправить команду с рассчитанными данными (которые на самом деле , является реакцией на переход).

Помогает ли это немного прояснить ситуацию?

PS: Может быть, это также помогло бы быть более точным в именовании, например. иметь paused и resumed вместо pauseSwitched. Это потребовало бы меньше логики, чтобы выяснить намерение того, что произошло, и это, по сути, одна из сильных сторон DDD, чтобы иметь возможность быть явными в формулировках. Потому что, как это называется прямо сейчас, это скорее какое-то событие updated (которого следует избегать).

person Golo Roden    schedule 23.08.2018
comment
Я полностью согласен с вашими комментариями к самому коду, я собрал его в спешке. Особой причины для использования потока не было, я просто подумал, что это будет самое элегантное решение. Я думаю, что я выберу ваше второе решение. - person Thomas Pötzsch; 23.08.2018