我最近一直在调查活动采购,对与客户的互动有一些问题。
所以事件源听起来很棒。解耦你所有的微服务,将你的信息保存在不可变事件中,并根据你的需求制定一个存储状态,这真的很方便。让事件通过你的系统/服务传播,并以他们自己的方式对事件做出反应。
我遇到的问题在于理解客户端交互。
所以你希望客户端与系统交互,但是他们现在需要通过事件来实现。他们不能再提交一个状态来改变你现有的状态。
因此,问题是客户端如何启动特定事件并与(不仅是基于事件的系统)而且是基于事件源的系统进行交互。
我的理解是,您不再将其余api用作资源(您可以获取、更新、删除等...将它们作为资源处理),而是将其作为事件发布到endpoint。
那么这些endpoint是如何工作的呢?
我的第二个问题是用户如何得到响应?例如,假设我们有一个事件要下订单。你要启动一个事件,它会做它的事情。再一次,我的理解是,你现在不验证请求,例如检查用户订购订单是否有足够的钱,而是发射它被放置,它将在系统中处理。例如,它不会被-订单放置-这将由定价服务拾取,它将发射预留资金或基于用户是否负担得起的资金超过事件。-订单服务将监听这些,然后将订单标记为拒绝或信用不足。
因此,因为这是一个异步过程,用户已经启动并忘记了,那么您如何向用户显示它已经失败或成功?你是给他们看一个订单确认页面,订单状态保持不变(即使是挂起的),还是轮询它,直到它发生变化(网络套接字或其他)。
我很抱歉,如果这些都是胡说八道,我仍然在学习这个架构,而且我的思维方式非常像一个拥有REST响应的巨石。
任何帮助都将不胜感激。
所以你希望客户端与系统交互,但是他们现在需要通过事件来做到这一点。
客户不必这么做。客户端甚至可能不知道底层事件存储。
在实现事件源系统时,需要考虑许多权衡和决策。首先,你可以试着举出几个前计算机时代事件源系统的例子,看看它们的非功能特性。
所以问题是客户端如何触发特定事件
客户端不发送事件。他们应该表达意图(命令)。然后,来自事件的系统有责任验证意图并拒绝它或接受并存储相应的事件。这意味着改变系统状态的意图被接受,存储的事件确认了改变。
我的理解是,您不再使用rest api,因为rest是一种选择。你只是把不同的东西看作是资源。命令可以是REST资源。事件源实体可以是资源,您可以向其发布命令。如果您喜欢异步-您可以稍后获取命令来检查其状态。您可以让实体了解其当前状态。您无法通过订阅从一类实体获取事件。
如果我们谈论的是最终用户,那么很可能它不直接处理事件存储。中间有一些第三层,用于CQRS。从用户客户端的角度来看,它可以通过REST、GraphQL、SOAP、gRPC或事件电子邮件提供。无论您认为合适的传输解决方案是什么。CQRS的命令处理部分是专门由域驱动的。它决定接受哪个意图,拒绝哪个意图。
事件存储本身负责数据的一致性。一、 e.不允许发布导致无效状态的两个并发事件。这就是前计算机事件源系统擅长的。您通常将一些物理对象作为一个实体,因此您只需获得它即可锁定更新。
然后,最终用户客户端通常从一些准备好的读取模型中读取。读取(CQRS中的R)组件的职责是为客户端准备读取优化数据。这些数据可能来自相同或不同类别的多个事件。同样,客户端可以使用任何合适的传输与读取模型交互。
虽然事件存储是一致且立即一致的,但读取模型最终是一致的。但这取决于你来调整这种可能性。
试着把其余的部分从架构中去掉一段时间。将其视为可用的传输选项之一,这可能有助于了解其根源。
我遇到的问题在于理解客户端交互。
有些问题可能是理解的,但我向你们保证,一个公平的问题是,文学很烂。
特别是,“事件”这个词被以许多不同的方式重复使用。如果你不非常仔细地注意所使用的意思,你会被打结的。
事件源实际上是关于持久性的——微服务器如何存储其状态的私有副本以供以后重用?我们没有破坏性地覆盖我们以前的状态,而是编写链接回以前状态的新信息。如果您想象每个微服务将每个状态更改作为提交存储在自己的git存储库中,那么您就大体正确了。
这与使用事件消息在一个微服务和另一个微服务之间传递信息是不同的。
当然,这里有一些明显的重叠,因为您可能会与其他微服务共享的一条消息是“我刚刚改变了状态”。
那么这些endpoint是如何工作的呢?
与web表单的方式相同。我向您发送一个表单的表示,客户机将表单显示给您。您填写数据并提交表单,客户端处理表单的内容,然后向我发送一个HTTP请求,消息体中有一个“FormSubmitted”事件。
您可以通过发送新的状态表示来获得类似的结果,但这有点错误,容易去掉语义意图,然后在服务器上再次尝试猜测。因此,您更可能看到基于任务的用户界面,或明确标识更改语义的协议。
当外部世界是某些数据(例如,购物者的发货地址)的权威时,您更有可能看到更传统的“只编辑现有表示”方法。
因此,因为这是一个异步过程,用户已经启动并忘记了,那么您如何向用户显示它已经失败或成功?
在一个不可靠的网络上,Fire并忘记
确实不适用于分布式协议。在大多数情况下,至少一次传递很重要,所以Fire直到验证
是更常见的选项。消息的初始确认可能类似于202接受-“我们收到了您的消息,我们把它写了下来,这是我们当前的进度,这里有一些您可以获取进度报告的链接”。
在我看来,事件源并不适合传统的REST模型,在REST模型中,您可以对资源进行CRUD。
Jim Webber 2011年的演讲可能有助于消除噪音。REST API是您的域模型所穿的伪装;您交换有关操作资源的消息,作为副作用,您的域模型做了有用的工作。
一种看起来更“传统”的方法是使用事件流的表示。我执行一个GET/08ff2ec9-a9ad-4be2-9793-18e232dbe615,它返回事件列表的表示。我将一个新事件附加到该列表的末尾,然后PUT/08ff2ec9-a9ad-4be2-9793-18e232dbe615,就会发生有趣的副作用。或者,我可以创建一个描述我的更改的补丁文档,然后创建一个补丁/08ff2ec9-a9ad-4be2-9793-18e232dbe615。
但更可能的是,我会做一些其他的事情,而不是获取事件列表的表示,我可能会获取可用协议的表示,也就是说,一个充满超链接的文档。从那里,我可以获得数据收集表单的表示形式。我填写活动的详细信息,提交表单,然后将表单数据发送到服务器。
当然,您可以对URI使用任何您喜欢的拼写。
在第一种情况下,我们需要类似于支持HTTP的文档编辑器的东西;第二种情况使用更像Web浏览器的东西。
如果有许多不同类型的事件,那么第二种情况很可能有许多不同的表单资源,都提交POST /08ff2ec9-a9ad-4be2-9793-18e232dbe615
请求。
(您不必将所有表单提交到同一个URI,但需要考虑一些优势)。
在非事件源模式中,我想这将首先放入数据库,然后事件上升。
即使您不是事件源,在发布事件之前将事件提交到持久存储区也可能有一些优势。参见Pat Helland:外部数据与内部数据。
客户端事件通过 SetEvent 方法进行设置。 客户端事件有两个,它们分别定义为: type onErrorEvent interface { OnError(name string, err error) } type onFailswitchEvent interface { OnFailswitch(Client) } 因为 go 语言不需要显式实现接口的特点,所以这两
脚本 我正在使用微服务构建快递服务系统。我不确定一些事情,这是我的场景 预订API-这是客户下订单的地方 付款API-这是我们处理预订付款的地方 通知API-有服务负责在一切完成后发送通知。 系统采用事件驱动架构。当客户下预订订单时,我在预订应用编程接口中提交本地交易并发布事件。支付应用编程接口和通知应用编程接口订阅了各自的事件。一旦完成,支付和通知应用编程接口需要向预订应用编程接口确认。 我的问
本文向大家介绍详解php与ethereum客户端交互,包括了详解php与ethereum客户端交互的使用技巧和注意事项,需要的朋友参考一下 php与ethereum rpc server通信 一、Json RPC Json RPC就是基于json的远程过程调用,这么解释比较抽象。简单来说,就是post一个json格式的数据调用rpc server中的方法. 而这个json格式是固定的, 总的来说有
客户端交互性 所有的WebDAV客户端分为三类—独立应用程序,文件浏览器扩展或文件系统实现,这些分类定义了WebDAV用户可用的功能性。表 C.1 “常用WebDAV客户端”给WebDAV常见软件进行了分类,并提供了的简短描述。 表 C.1. 常用WebDAV客户端 软件 类型 Windows Mac Linux 描述 Adobe Photoshop 独立的WebDAV应用程序 X 图像编辑软件,
KSVC KSVC(Kingsoft Video Cloud)是金山云提供的移动端SDK。金山云在编解码方面动作比较多,支持了h.265。 编码器特性: Android iOS Codec Transport Hardware Encoder Software Encoder Lowlatency YES YES H.264+AAC H.265 RTMP YES YES NO 编码器高级特性: 美
问题 你需要通过HTTP协议以客户端的方式访问多种服务。例如,下载数据或者与基于REST的API进行交互。 解决方案 对于简单的事情来说,通常使用 urllib.request 模块就够了。例如,发送一个简单的HTTP GET请求到远程的服务上,可以这样做: from urllib import request, parse # Base URL being accessed url = 'ht