Wow 2.6.12 发布,API 写性能轻松超 2W TPS


【源创会预告】1024 程序员节(的前两天),相约开源PHP办公室,我们一起聊 AI!>>>

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

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

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

更新内容 🎉 🎉 🎉

  • 依赖: 更新 org.springframework.boot:spring-boot-dependencies 版本 v3.1.5
  • 依赖: 更新 com.google.guava:guava 版本 v32.1.3-jre
  • 依赖: 更新 io.swagger.core.v3:swagger-core-jakarta 版本 v2.2.17
  • 依赖: 更新 io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom 版本 v1.31.0
  • 依赖: 更新 org.jetbrains.dokka 版本 v1.9.10
  • 修复: 路由路径参数(tenantId/id)冗余定义
  • 文档: 新增 Example API 性能测试报告(Example)

性能测试报告

加入购物车

WaitStrategy: SENT

SENT

WaitStrategy: PROCESSED

PROCESSED

下单

WaitStrategy: SENT

SENT

WaitStrategy: PROCESSED

PROCESSED

架构图

Wow-Architecture

事件源

Wow-EventSourcing

可观测性

Wow-Observability

OpenAPI (Spring WebFlux 集成)

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

Wow-Spring-WebFlux-Integration

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

Given -> When -> Expect .

Wow-CI-Flow

前置条件

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

特性

  •  Aggregate Modeling
    •  Single Class
    •  Inheritance Pattern
    •  Aggregation Pattern
  •  Saga Modeling
    •  StatelessSaga
  •  Test Suite
    •  兼容性测试规范(TCK)
    •  AggregateVerifier
    •  SagaVerifier
  •  EventSourcing
    • EventStore
      •  MongoDB (Recommend)
      •  R2dbc
        •  Database Sharding
        •  Table Sharding
      •  Redis
    • Snapshot
      •  MongoDB
      •  R2dbc
        •  Database Sharding
        •  Table Sharding
      •  ElasticSearch
      •  Redis (Recommend)
  •  命令等待策略(WaitStrategy
    •  SENT : 命令发送成功后发送完成信号
    •  PROCESSED : 命令处理完成后发送完成信号
    •  SNAPSHOT : 快照生成完成后发送完成信号
    •  PROJECTED : 命令产生的事件被投影后发送完成信号
  •  CommandBus
    •  InMemoryCommandBus
    •  KafkaCommandBus (Recommend)
    •  RedisCommandBus
    •  LocalFirstCommandBus
  •  DomainEventBus
    •  InMemoryDomainEventBus
    •  KafkaDomainEventBus (Recommend)
    •  RedisDomainEventBus
    •  LocalFirstDomainEventBus
  •  StateEventBus
    •  InMemoryStateEventBus
    •  KafkaStateEventBus (Recommend)
    •  RedisStateEventBus
    •  LocalFirstStateEventBus
  •  Spring 集成
    •  Spring Boot Auto Configuration
    •  Automatically register CommandAggregate to RouterFunction
  •  可观测性
    •  OpenTelemetry
  •  OpenAPI
  •  WowMetadata Generator
    •  wow-compiler

Example

Example

单元测试套件

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

Test Coverage

Given -> When -> Expect .

Aggregate Unit Test (AggregateVerifier)

Aggregate Test

internal class OrderTest {

private fun mockCreateOrder(): VerifiedStage<OrderState> {
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()
}
}
return 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 createOrder() {
mockCreateOrder()
}

@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()
}

/**
 * 创建订单-下单价格与当前价格不一致
 */
@Test
fun createOrderWhenPriceInconsistency() {
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.plus(BigDecimal.valueOf(1)) }.first().toMono()
}
}
aggregateVerifier<Order, OrderState>()
.inject(DefaultCreateOrderSpec(inventoryService, pricingService))
.given()
.`when`(CreateOrder(customerId, orderItems, SHIPPING_ADDRESS, false))
/*
 * 期望:价格不一致异常.
 */
.expectErrorType(PriceInconsistencyException::class.java).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

Saga - OrderProcessManager (Demo)

OrderProcessManager

性能测试 (Example)

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

部署

  • Redis
  • MongoDB
  • Kafka
  • Application-Config
  • Application-Deployment

测试报告

加入购物车

  • 请求
  • 详细报告 (PDF)-SENT
  • 详细报告 (PDF)-PROCESSED

WaitStrategy: SENT

SENT

WaitStrategy: PROCESSED

PROCESSED

下单

  • 请求
  • 详细报告 (PDF)-SENT
  • 详细报告 (PDF)-PROCESSED

WaitStrategy: SENT

SENT

WaitStrategy: PROCESSED

PROCESSED


相關推薦

2024-01-11

本次更新: 1. select(vo) 自动帮助你选择需要select的列 2. 增加@Fetch 注解,实现结果1对1,1对多,让不想写join的同学,方便快捷 mybatis-mp 包含丰富的 api: 1:基于注解,映射数据库; 2:支持多表 join 和返回; 3:api 采用 lamb

2023-09-14

商业化产品作为 TDMQ 产品家族的新成员在本次大会上重磅发布。 TDMQ RocketMQ 版是一款分布式高可用的消息队列服务,兼容 Apache RocketMQ 的各个组件与概念,支持开源客户端零改造接入,同时具备计算存储分离,灵活扩缩容的底

2023-02-10

CosId 通用、灵活、高性能分布式 ID 生成器       更新内容(v1.17.0) 🎉 🎉 🎉 ⭐ 特性 特性: 新增 MongoDb 号段分发器 简介 CosId 旨在提供通用、灵活、高性能的分布式 ID 生成器。

2023-10-26

CosId 通用、灵活、高性能分布式 ID 生成器 更新内容 🎉 🎉 🎉新增 Flowable IdGenerator 支持特性:新增 FlowableIdGenerator 支持依赖:新增 FlowableIdGeneratorAutoConfiguration 支持自动配置依赖:更新 spring

2023-11-02

CosId 通用、灵活、高性能分布式 ID 生成器      更新内容 🎉 🎉 🎉 新增 Activiti IdGenerator 支持 特性:新增 ActivitiIdGenerator 支持 依赖:新增 ActivitiIdGeneratorAutoConfiguration 支

2022-10-30

CosId 通用、灵活、高性能分布式 ID 生成器       更新内容( v2.0.0-RC1) 🎉 🎉 🎉 🔨 依赖更新 适配 org.springframework.boot:spring-boot-dependencies 3.0.0-RC1 代码基线升级到 Java 17 (Spring boot

2023-08-05

;@CosId,主键自动赋值 特性:新增 cosid-proxy 镜像发布仓库(registry.cn-shanghai.aliyuncs.com/ahoo/cosid-proxy) 便于国内用户使用 特性:增强 cosid-proxy OpenAPI 支持   简介 CosId 旨在提供通用、灵活、高性能的分布

2023-06-30

CosId 通用、灵活、高性能分布式 ID 生成器       更新内容(v2.2.0) 🎉 🎉 🎉 特性:支持 分组号段分发器(GroupedIdSegmentDistributor) share: group: by: year converter: type: to_string to-string: pad-start: true

2022-10-30

CosId 通用、灵活、高性能分布式 ID 生成器       更新内容(v1.15.2) 🎉 🎉 🎉 ⭐ 特性增强 测试覆盖率提升: Snowflake 算法分片均匀性 增强: CosIdIntervalShardingAlgorithm 支持更多日期类型:

2023-02-23

ZQPool 是一个可以替代 pgbouncer 的连接池软件 ,在 1.2 版本中主要做了一下改进: 1. 之前的版本不支持文本大小超过64K的SQL语句,新版本没有此限制了; 2. 连接池上增加了参数msg_buf_size,可以指定接收或发送消息的缓冲区默认大

2023-02-11

ZQPool 是一个可以替代 pgbouncer 的连接池软件 ,在1.1版本中主要做了一下改进: 之前的版本,前端连接过来的用户名和数据库名称必须与后端数据库中的完全一样,现在可以不一样。例如原先的版本如果使用scott用户连接ZQPool

2023-07-11

持从项目外部加载源代码来生成字段注释 (包括标准规范发布的 jar 包)。 支持生成多种格式文档:Markdown、HTML5、Asciidoctor、Postman collection、Open Api 3.0+。 轻易实现在 Spring Boot 服务上在线查看静态 HTML5 api 文档。 开放文档数据

2023-04-24

前 Deepin CTO 王勇近日在社交网站发布招聘信息时,提到了他们团队对于各种编程语言的丰富使用经历。 接着他本人谈论了一些关于各种编程语言的感悟,其中包括 Golang、Rust、Java、Python,甚至提到了比较小众的 Vala。下面是对

2024-01-19

Wine 9.0 稳定版已正式发布。 Wine (“Wine Is Not an Emulator” 的首字母缩写)是一个能够在多种 POSIX-compliant 操作系统(诸如 Linux,macOS 及 BSD 等)上运行 Windows 应用的兼容层。它不是像虚拟机或者模拟器一样模仿内部的 Windows 逻