wolkenkit中的自复位循环流

Self-resetting circular flow in wolkenkit

我对有状态流有疑问,我将尝试将其分解为一个非常简单的示例: 我正在使用不同的状态,可以说是原始状态、添加状态和计算状态。 我的状态包含一个我要添加的 int,在我添加两次之后,我想计算翻倍的数量,然后再次将其设置为原始状态。 所以现在我将从原始流程开始,int = 0。在我的转换中,我对 addNumber 事件做出反应,从事件数据中取出一个 int 并将其添加到我的状态,然后我 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

基本上,对此有两种想法:

  1. 第一个选项是质疑你是否应该在这里使用流。也许你可以将其建模为一个聚合,使用 startWorkendWorkpauseresume 等命令,以及所需的状态,然后你就可以拥有你想要的逻辑想要拥有那个聚合的内部。您可以为每个人使用一个聚合,或者为每个存在块使用一个聚合。无论哪种方式,这都应该有效。因此,换句话说:是否有特殊原因为什么要将其实现为流而不是聚合?
  2. 第二个选项是pristinecalculating没有区别。因为,您实际上想要的是某种圆圈,但您的流程并未建模为圆圈。因此,如果不是最终过渡到 calculating,而是过渡回 pristine,您将处于所需的状态,并且在 present->pristine 的反应内部,您可以进行您想要的计算并发送带有计算数据的命令(实际上,对转换的反应)。

这是否有助于澄清一些事情?

PS:也许在命名时更加明确也会有所帮助,例如有 pausedresumed 而不是 pauseSwitched。这将需要更少的逻辑来弄清楚所发生事情的意图,这基本上是 DDD 的优势之一,能够在措辞中明确表达。因为,正如它现在的名称,它更像是某种 updated 事件(应该避免)。