我正在 KTOR 中测试一个事件驱动的架构。我的核心逻辑保存在一个类中,该类对 StateFlow 发出的不同事件类型作出反应。EventGenerators 将事件推送到由 Core 拾取的 StateFlow 中。
但是,当核心尝试响应ApplicationCall
嵌入在我的一个事件中的事件时,我会收到一个ResponseAlreadySentException
,但我不确定为什么会这样。如果我绕过 StateFlow 并直接从 EventGenerator 调用 Core 类,则不会发生这种情况。我在代码中的其他任何地方都没有响应 ApplicationCalls,并且已经用断点检查了唯一的.respond
行没有被多次命中。
MyStateFlow 类:
class MyStateFlow {
val state: StateFlow<CoreEvent>
get() = _state
private val _state = MutableStateFlow<CoreEvent>(CoreEvent.NothingEvent)
suspend fun update(event: CoreEvent) {
_state.value = event
}
}
我的核心课程:
class Core(
myStateFlow: MyStateFlow,
coroutineContext: CoroutineContext = SupervisorJob() + Dispatchers.IO
) {
init {
CoroutineScope(coroutineContext).launch {
myStateFlow.state.collect {
onEvent(it)
}
}
}
suspend fun onEvent(event: CoreEvent) {
when(event) {
is FooEvent {
event.call.respond(HttpStatusCode.OK, "bar")
}
...
}
}
}
我的 EventGenerator 之一是我的 KTOR 应用程序类中的路由:
get("/foo") {
myStateFlow.update(CoreEvent.FooEvent(call))
}
但是,/f00
在我的浏览器中点击会返回一条ResponseAlreadySentException
或一条java.lang.UnsupportedOperationException
带有消息:“无法再设置标题,因为响应已经完成”。当我在尝试不同的解决方案时,错误响应可以在两者之间切换,但它们似乎在说同样的事情:在我尝试调用之前,调用已经得到响应call.respond(...)
。
如果我改变我的路线而不是直接调用Core.onEvent()
,点击/foo
在我的浏览器中返回“栏”,这是预期的行为:
get("/foo") {
core.onEvent(CoreEvent.FooEvent(call))
}
为了完整起见,我的依赖版本是:
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.10"
implementation "io.ktor:ktor-server-netty:1.4.1"
提前感谢您提供的任何见解。