假设我有这样的工作流程
(1) Check for latest commit in a GitHub repo
|
|
(2) Is new commit?
/ \
No / \ Yes
/ \
/ \
End \
\
\
(3) Download all files
/ | \
/ | \
(4i) Process file i . Process file N
\ . /
\ . /
\ . /
\ . /
\ . /
End
我想拥有以下微服务:
我的问题是,这些微服务中的每一个是否应该是顺序工作流中的链接,还是这些微服务是否应该仅包含功能,而单独的“无所不知”微服务负责工作流?
在第一种情况下,可能看起来像
A: (1),(2) ====> B:(3) ====> C:(4i),(4ii),...,(4N)
每个链接将消息写入队列中的消息,然后由下一个链接拾取。
因为(2)在A中,这意味着A正在决定是否调用B。我猜您可以说这两个服务紧密耦合。
在我建议的其他实现中,将有一个单独的服务X执行控制流,并将数据简单地插入到A,B,C中,这将执行诸如以下的单个任务
A: Get latest commit
B: Download all files by commit
C: Process single file
然后X将拥有/执行的逻辑
哪个实施更好?
我还有一个关于存储的问题。 Is new commit?
部分意味着我保留了一份提交记录,因此我可以知道我检查的内容是否是我以前从未检查过的内容。 谁应该保留提交记录?应该在A的存储中还是单独的“工作流存储”中考虑它?
答案 0 :(得分:1)
我要解决的方法是成为Chain of Responsibilities
,其中每个节点负责检查条件或完成工作
例如,您的第一阶段是一个合理的决定:
因此,每个节点都有可能执行终止功能(可能会/可能不会返回结果;我的功能主义者说应该这样做)。
从编码角度看,它可能像这样:
interface Responsibility<I> {
fun apply(context:I) : Unit?
}
class GitRepo{
val files = setOf<URI>()
val commiters = setOf<String>()
fun hasNewCommit() = true
}
abstract class Chained<I,N>(protected val next:Responsibility<N>) : Responsibility<I> {
}
class CheckCommited(next:Responsibility<Set<URI>>) : Chained<GitRepo,Set<URI>>(next) {
override fun apply(gr:GitRepo) = when(gr.hasNewCommit()) {
true -> next.apply(gr.files)
false -> null
}
}
class DownLoadFiles(next:Responsibility<Set<URL>>) : Chained<Set<URI>,Set<URL>>(next) {
override fun apply(uris:Set<URI>) {
next.apply(uris.map { downLoad(it) }.toSet())
}
fun downLoad(uri:URI): URL {
return uri.toURL()
}
}
class NotifyPeople(val people: Set<String>) : Responsibility<Set<URL>> {
override fun apply(context: Set<URL>): Unit? {
people.forEach { context.forEach { sendMail(it.toString()) }}
}
private fun sendMail(email: String) {
}
}
val root = CheckCommited(DownLoadFiles(NotifyPeople(setOf("joe@company.com","suzy@someplace.other"))))
答案 1 :(得分:1)
那不是微服务。这是微微服务,恕我直言,它们是小型的,可以激发微服务所需的所有额外维护和管理。在GOTO Conference 2014的精彩演讲中,Martin Fowler建议为每个微服务推荐几个全职开发人员。如果您没有至少一个可以全天候使用该服务的设备,那么它的体积就会很小。
为简单起见,您可以改用基于消息的体系结构,其中每个内部服务都订阅来自其他内部服务的消息。
例如,下载完成后,您可以从FileDownloaded
发送一个FileDownloader
已订阅的FileProcessor
事件。这样,它们之间也不会紧密耦合。
对于消息传递库,例如,您可以使用我的messaging library