🎉 领域模型即服务 | Wow 2.12.1 发布

Wow:基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架

License GitHub release Codacy Badge codecov Integration Test Status Awesome Kotlin Badge

领域驱动 | 事件驱动 | 测试驱动 | 声明式设计 | 响应式编程 | 命令查询职责分离 | 事件溯源

更新内容

增强 事件补偿控制台

  • 特性(dashboard): 支持在事件补偿控制台配置执行失败的重试策略
  • 特性(dashboard): 支持查看事务补偿-历史记录
  • 特性(dashboard): 添加事件补偿-正在执行导航
  • 特性(dashboard): 添加事件补偿通知快速打开执行失败链接
  • 特性(OpenAPI): 添加 SnapshotConverter/StateEventConverter/EventStreamConverter/DomainEventConverter 以适配 Wow 内置序列化器 - OpenAPI-Schema
  • 特性(CommandGateawy): 添加sendAndWaitForSnapshotAPI
  • 依赖: 升级 org.springframework.boot:spring-boot-dependencies v3.2.1
  • 依赖: 升级 org.jetbrains.kotlin.kapt v1.9.22
  • 依赖: 升级 angular v17.0.8

事件补偿控制台

事件补偿控制台
事件补偿控制台-重试策略
事件补偿控制台-查看异常
事件补偿控制台-成功

快速开始

使用 Wow 项目模板快速创建基于 Wow 框架的 DDD 项目。

特性概览

Wow-Features

架构图

Wow-Architecture

性能测试 (Example)

  • 测试代码:Example
  • 测试场景:加入购物车、下单
  • 命令发送等待模式(WaitStrategy):SENTPROCESSED

部署

测试报告

加入购物车

命令等待策略(WaitStrategy)为 SENT 模式,加入购物车命令(AddCartItem)写请求 API 经过 2 分钟的压测,平均 TPS 为 59625,峰值为 82312,平均响应时间为 29 毫秒。

SENT

命令等待策略(WaitStrategy)为 PROCESSED 模式,加入购物车命令(AddCartItem)写请求 API 经过 2 分钟的压测,平均 TPS 为 18696,峰值为 24141,平均响应时间为 239 毫秒。

PROCESSED

下单

命令等待策略(WaitStrategy)为 SENT 模式,下单命令(CreateOrder)写请求 API 经过 2 分钟的压测,平均 TPS 为 47838,峰值为 86200,平均响应时间为 217 毫秒。

 

SENT

命令等待策略(WaitStrategy)为 PROCESSED 模式,下单命令(CreateOrder)写请求 API 经过 2 分钟的压测,平均 TPS 为 18230,峰值为 25506,平均响应时间为 268 毫秒。

CreateOrder-PROCESSED

事件源

Wow-EventSourcing

可观测性

Wow-Observability

OpenAPI (Spring WebFlux 集成)

自动注册 命令 路由处理函数 (HandlerFunction) ,开发人员仅需编写领域模型,即可完成服务开发。

Wow-Spring-WebFlux-Integration

测试套件:80%+ 的测试覆盖率轻而易举

Given -> When -> Expect .

Wow-CI-Flow

前置条件

  • 理解 领域驱动设计:《实现领域驱动设计》、《领域驱动设计:软件核心复杂性应对之道》
  • 理解 命令查询职责分离(CQRS)
  • 理解 事件源架构
  • 理解 响应式编程

Example

订单服务(Kotlin)

Example-Order

银行转账(JAVA)

Example-Transfer

单元测试套件

80%+ 的测试覆盖率轻而易举。

Test Coverage

Given -> When -> Expect .

Aggregate Unit Test (AggregateVerifier)

Aggregate Test

internal class OrderTest {

    @Test
    private fun createOrder() {
        val tenantId = GlobalIdGenerator.generateAsString()
        val customerId = GlobalIdGenerator.generateAsString()

        val orderItem = OrderItem(
            GlobalIdGenerator.generateAsString(),
            GlobalIdGenerator.generateAsString(),
            BigDecimal.valueOf(10),
            10,
        )
        val orderItems = listOf(orderItem)
        val inventoryService = object : InventoryService {
            override fun getInventory(productId: String): Mono<Int> {
                return orderItems.filter { it.productId == productId }.map { it.quantity }.first().toMono()
            }
        }
        val pricingService = object : PricingService {
            override fun getProductPrice(productId: String): Mono<BigDecimal> {
                return orderItems.filter { it.productId == productId }.map { it.price }.first().toMono()
            }
        }
        aggregateVerifier<Order, OrderState>(tenantId = tenantId)
            .inject(DefaultCreateOrderSpec(inventoryService, pricingService))
            .given()
            .`when`(CreateOrder(customerId, orderItems, SHIPPING_ADDRESS, false))
            .expectEventCount(1)
            .expectEventType(OrderCreated::class.java)
            .expectStateAggregate {
                assertThat(it.aggregateId.tenantId, equalTo(tenantId))
            }
            .expectState {
                assertThat(it.id, notNullValue())
                assertThat(it.customerId, equalTo(customerId))
                assertThat(it.address, equalTo(SHIPPING_ADDRESS))
                assertThat(it.items, equalTo(orderItems))
                assertThat(it.status, equalTo(OrderStatus.CREATED))
            }
            .verify()
    }

    @Test
    fun createOrderGivenEmptyItems() {
        val customerId = GlobalIdGenerator.generateAsString()
        aggregateVerifier<Order, OrderState>()
            .inject(mockk<CreateOrderSpec>(), "createOrderSpec")
            .given()
            .`when`(CreateOrder(customerId, listOf(), SHIPPING_ADDRESS, false))
            .expectErrorType(IllegalArgumentException::class.java)
            .expectStateAggregate {
                /*
                 * 该聚合对象处于未初始化状态,即该聚合未创建成功.
                 */
                assertThat(it.initialized, equalTo(false))
            }.verify()
    }

    /**
     * 创建订单-库存不足
     */
    @Test
    fun createOrderWhenInventoryShortage() {
        val customerId = GlobalIdGenerator.generateAsString()
        val orderItem = OrderItem(
            GlobalIdGenerator.generateAsString(),
            GlobalIdGenerator.generateAsString(),
            BigDecimal.valueOf(10),
            10,
        )
        val orderItems = listOf(orderItem)
        val inventoryService = object : InventoryService {
            override fun getInventory(productId: String): Mono<Int> {
                return orderItems.filter { it.productId == productId }
                    /*
                     * 模拟库存不足
                     */
                    .map { it.quantity - 1 }.first().toMono()
            }
        }
        val pricingService = object : PricingService {
            override fun getProductPrice(productId: String): Mono<BigDecimal> {
                return orderItems.filter { it.productId == productId }.map { it.price }.first().toMono()
            }
        }

        aggregateVerifier<Order, OrderState>()
            .inject(DefaultCreateOrderSpec(inventoryService, pricingService))
            .given()
            .`when`(CreateOrder(customerId, orderItems, SHIPPING_ADDRESS, false))
            /*
             * 期望:库存不足异常.
             */
            .expectErrorType(InventoryShortageException::class.java)
            .expectStateAggregate {
                /*
                 * 该聚合对象处于未初始化状态,即该聚合未创建成功.
                 */
                assertThat(it.initialized, equalTo(false))
            }.verify()
    }
}

Saga Unit Test (SagaVerifier)

Saga Test

class CartSagaTest {

    @Test
    fun onOrderCreated() {
        val orderItem = OrderItem(
            GlobalIdGenerator.generateAsString(),
            GlobalIdGenerator.generateAsString(),
            BigDecimal.valueOf(10),
            10,
        )
        sagaVerifier<CartSaga>()
            .`when`(
                mockk<OrderCreated> {
                    every {
                        customerId
                    } returns "customerId"
                    every {
                        items
                    } returns listOf(orderItem)
                    every {
                        fromCart
                    } returns true
                },
            )
            .expectCommandBody<RemoveCartItem> {
                assertThat(it.id, equalTo("customerId"))
                assertThat(it.productIds, hasSize(1))
                assertThat(it.productIds.first(), equalTo(orderItem.productId))
            }
            .verify()
    }
}

设计

聚合建模

Single Class Inheritance Pattern Aggregation Pattern
Single Class - Modeling Inheritance Pattern- Modeling Aggregation Pattern- Modeling

加载聚合

Load Aggregate

聚合状态流

Aggregate State Flow

发送命令

Send Command

命令与事件流

Command And Event Flow

事件补偿

用例图

Event-Compensation-UserCase

执行时序图

Event-Compensation

Dashboard

Compensation-Dashboard

Compensation-Dashboard-Error

优秀的个人博客,低调大师

微信关注我们

原文链接:https://www.oschina.net/news/272439

转载内容版权归作者及来源网站所有!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

相关文章

发表评论

资源下载

更多资源
Mario,低调大师唯一一个Java游戏作品

Mario,低调大师唯一一个Java游戏作品

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Oracle Database,又名Oracle RDBMS

Oracle Database,又名Oracle RDBMS

Oracle Database,又名Oracle RDBMS,或简称Oracle。是甲骨文公司的一款关系数据库管理系统。它是在数据库领域一直处于领先地位的产品。可以说Oracle数据库系统是目前世界上流行的关系数据库管理系统,系统可移植性好、使用方便、功能强,适用于各类大、中、小、微机环境。它是一种高效率、可靠性好的、适应高吞吐量的数据库方案。

Eclipse(集成开发环境)

Eclipse(集成开发环境)

Eclipse 是一个开放源代码的、基于Java的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。幸运的是,Eclipse 附带了一个标准的插件集,包括Java开发工具(Java Development Kit,JDK)。

Java Development Kit(Java开发工具)

Java Development Kit(Java开发工具)

JDK是 Java 语言的软件开发工具包,主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个java开发的核心,它包含了JAVA的运行环境(JVM+Java系统类库)和JAVA工具。