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
基本上,对此有两种想法:
- 第一个选项是质疑你是否应该在这里使用流。也许你可以将其建模为一个聚合,使用
startWork
、endWork
、pause
和 resume
等命令,以及所需的状态,然后你就可以拥有你想要的逻辑想要拥有那个聚合的内部。您可以为每个人使用一个聚合,或者为每个存在块使用一个聚合。无论哪种方式,这都应该有效。因此,换句话说:是否有特殊原因为什么要将其实现为流而不是聚合?
- 第二个选项是
pristine
和calculating
没有区别。因为,您实际上想要的是某种圆圈,但您的流程并未建模为圆圈。因此,如果不是最终过渡到 calculating
,而是过渡回 pristine
,您将处于所需的状态,并且在 present->pristine
的反应内部,您可以进行您想要的计算并发送带有计算数据的命令(实际上,是对转换的反应)。
这是否有助于澄清一些事情?
PS:也许在命名时更加明确也会有所帮助,例如有 paused
和 resumed
而不是 pauseSwitched
。这将需要更少的逻辑来弄清楚所发生事情的意图,这基本上是 DDD 的优势之一,能够在措辞中明确表达。因为,正如它现在的名称,它更像是某种 updated
事件(应该避免)。
我对有状态流有疑问,我将尝试将其分解为一个非常简单的示例:
我正在使用不同的状态,可以说是原始状态、添加状态和计算状态。
我的状态包含一个我要添加的 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
基本上,对此有两种想法:
- 第一个选项是质疑你是否应该在这里使用流。也许你可以将其建模为一个聚合,使用
startWork
、endWork
、pause
和resume
等命令,以及所需的状态,然后你就可以拥有你想要的逻辑想要拥有那个聚合的内部。您可以为每个人使用一个聚合,或者为每个存在块使用一个聚合。无论哪种方式,这都应该有效。因此,换句话说:是否有特殊原因为什么要将其实现为流而不是聚合? - 第二个选项是
pristine
和calculating
没有区别。因为,您实际上想要的是某种圆圈,但您的流程并未建模为圆圈。因此,如果不是最终过渡到calculating
,而是过渡回pristine
,您将处于所需的状态,并且在present->pristine
的反应内部,您可以进行您想要的计算并发送带有计算数据的命令(实际上,是对转换的反应)。
这是否有助于澄清一些事情?
PS:也许在命名时更加明确也会有所帮助,例如有 paused
和 resumed
而不是 pauseSwitched
。这将需要更少的逻辑来弄清楚所发生事情的意图,这基本上是 DDD 的优势之一,能够在措辞中明确表达。因为,正如它现在的名称,它更像是某种 updated
事件(应该避免)。