Wow 2.6.12 發布,API 寫性能輕松超 2W TPS

來源: 投稿
作者: Ahoo-Wang
2023-10-21 09:28:00

基于 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):SENT、PROCESSED

部署

測試報告

加入購物車

WaitStrategy: SENT

SENT

WaitStrategy: PROCESSED

PROCESSED

下單

WaitStrategy: SENT

SENT

WaitStrategy: PROCESSED

PROCESSED

展開閱讀全文
點擊加入討論??(2) 發布并加入討論??
2 評論
7 收藏
分享
返回頂部
頂部
一本久久综合亚洲鲁鲁五月天,无翼乌口工全彩无遮挡H全彩,英语老师解开裙子坐我腿中间