0

我一直在思考这个问题。一般来说,我尽量避免将服务注入我的域,但我有这种情况:

我有一个 PurchaseOrder 对象。使用某些服务(电子邮件或网络服务)将此订单发送给供应商。订单发送后,应向下订单的用户发送确认信息。

所以我意识到在这种情况下,领域事件将是实现发布 PurchaseOrderMade 事件的好方法。

然后我开始想:

如果订单没有发送,订单是否真的成功了?

您没有因为您决定做并写下来就下订单,而是在您按照合同无误地将其传送给供应商的时间下订单。

所以我重新决定并认为这毕竟可能属于域,所以我应该通过将 IPurchaseOrderSender 注入我的域来发送它,然后在成功交易后发布 OrderMadeEvent 并在 EventHandler 中发送确认。

理由是这样的:

  1. 订单的发送是流程的关键部分,可能会导致状态改变(即设置发送订单的标志)
  2. 确认并不重要,如果失败,订单仍然会进行,一切都会按计划进行。
  3. 它易于阅读,并且可以更改 IOrderService 的实现

问题是:

  1. 这真的有那么糟糕吗?
  2. 它是否违反了 DDD 的原则?
  3. 您以前是否遇到过这种情况并以更好的方式解决了它?

这是代码:

        public void MakeOrder(PurchaseOrder order, IPurchaseOrderSender orderSender)
    {
        if(PurchaseOrders == null)
            PurchaseOrders = new List<PurchaseOrder>();
        PurchaseOrders.Add(order);

        orderSender.Send(order);
        DomainEvents.Raise(new PurchaseOrderIsMade(){Order = order});
    }

    public interface IPurchaseOrderSender
{
    void Send(PurchaseOrder order);
}
4

1 回答 1

1

我以前遇到过这个,这是我做的:

使用远程过程调用拆分本地事务。

如果订单发送失败,我认为这没什么大不了的。在这种情况下,要么下单但未设置为“已发送”,要么回滚订单。如果订单未发送,则业务操作员可以进行干预,如果未下订单,则客户将致电。

但是下单成功后如果交易出现问题就很烦了。在这种情况下,如果订单被回滚,干预会更加困难,因为我们丢失了供应商的通知。通知通常包含供应商的订单标识符,因此我们可以在必要时取消带有此标识符的订单。

所以我们决定使用消息传递。
1) PlaceOrderService 负责存储订单并发送消息。
2)消息的消费者将订单发送给供应商,并发送包含供应商通知的消息。
3)通知消息的其他消费者更新订单状态。

每个步骤仅修改一个聚合或仅调用远程。

希望这可以帮助。

更新

1.你将如何在这里实现消息传递部分

我采用 Eric Evans 的 dddsample ApplicationEvents 中提到的解决方案。它只是一个简单的接口和一个 jms 实现,比如

    public void placeOrder(...) {// method in application service
        ....//order making
        orderRepository.store(order);
        applicationEvents.orderWasPlaced(order);//injected applicationEvents 
        //better move this step out of transaction boundary if not using 2pc commit
        //make the method returnning order and use decorator to send the message 
        //    placeOrder(...) {
        //        Order order = target.placeOrder(...);//transaction end here
        //        applicationEvents.orderWasPlaced(order);
        //        return order;
        //    }
    }

    public class JmsApplicationEvents implements ApplicationEvents {
        public void orderWasPlaced(Order order) {
             //sends the message using messaging api of your platform
        }
    }

2.I see you mention suppliers notification, but let's assume this is done through email (which will be the primary scenario here) I would like to know that the transaction was performed without errors (i.e. no smtp or connection failure), but cannot rely on a response that the order was actually received would that change anything?

hmm.. I have never build an trading application based on email, but here is my suggestions:

  1. Messaging solution still fits if you need strong consistency. Messaging is transactional and could involve in global transaction while email doesn't.

  2. Messaging provides more availability (your order making will not fail even if the mailserver is down) and scalability(queues).

  3. Failure handling is more difficult in messaging solution, usually needs compensating actions. And it's more difficult for the user to get the processing information. For example, you have to notify the user about the progress of the order processing since the following steps are asynchronous. And an email should be sent to the customer if the order is rejected by the supplier.

  4. But messaging does add extra complexity and takes you more effort to build and maintain. You have to evaluate is the gain worth the cost. Actually, I have also built several systems in synchronous solution(they don't require high throughput and availability), they works fine most of the time, only less than ten of orders fail due to the connection problem within a year, so it's not worthy to build an automatic error handling mechanism at all.

于 2013-10-25T06:50:51.720 回答