postgreSQL
sql
-- 创建 orders 表
CREATE TABLE orders (
id VARCHAR(36) PRIMARY KEY,
customer_id VARCHAR(36) NOT NULL,
status VARCHAR(20) NOT NULL,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NOT NULL,
gold_price DECIMAL(10, 2) NOT NULL,
currency VARCHAR(3) NOT NULL
);
-- 创建 order_items 表
CREATE TABLE order_items (
id SERIAL PRIMARY KEY,
order_id VARCHAR(36) REFERENCES orders(id),
product_id VARCHAR(50) NOT NULL,
weight_grams DECIMAL(10, 3) NOT NULL,
purity DECIMAL(4, 3) NOT NULL,
subtotal DECIMAL(12, 2) NOT NULL
);
项目结构:

Go
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bounded Parallelism Pattern 有界并行模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/5/29 22:13
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : bounded_executor.go
*/
package concurrency
import (
"context"
"sync"
)
type BoundedExecutor struct {
workerCount int
sem chan struct{}
wg sync.WaitGroup
}
func NewBoundedExecutor(maxWorkers int) *BoundedExecutor {
return &BoundedExecutor{
workerCount: maxWorkers,
sem: make(chan struct{}, maxWorkers),
}
}
func (e *BoundedExecutor) Submit(task func()) {
e.wg.Add(1)
go func() {
defer e.wg.Done()
// 等待获取信号量
select {
case e.sem <- struct{}{}:
defer func() { <-e.sem }()
task()
case <-context.Background().Done():
return
}
}()
}
func (e *BoundedExecutor) Shutdown(ctx context.Context) error {
done := make(chan struct{})
go func() {
e.wg.Wait()
close(done)
}()
select {
case <-done:
return nil
case <-ctx.Done():
return ctx.Err()
}
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bounded Parallelism Pattern 有界并行模式
# github.com/prometheus/client_golang/prometheus
# go get github.com/prometheus/client_golang/prometheus
# go get github.com/prometheus/client_golang/prometheus/promauto
# go get github.com/prometheus/client_golang/prometheus/promhttp
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/5/29 22:14
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : prometheus.go
*/
package metrics
import (
"github.com/prometheus/client_golang/prometheus"
"sync/atomic"
"time"
)
var (
workerPoolGauge = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "worker_pool_active_workers",
Help: "当前活跃的工作线程数",
},
[]string{"pool"},
)
queueLengthGauge = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "worker_pool_queue_length",
Help: "当前任务队列长度",
},
[]string{"pool"},
)
tasksCounter = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "worker_pool_tasks_total",
Help: "处理的任务总数",
},
[]string{"pool", "result"}, // result: success, failure
)
taskDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "worker_pool_task_duration_seconds",
Help: "任务处理耗时分布",
Buckets: []float64{0.001, 0.01, 0.1, 0.5, 1.0, 2.5, 5.0, 10.0},
},
[]string{"pool"},
)
)
func init() {
prometheus.MustRegister(workerPoolGauge)
prometheus.MustRegister(queueLengthGauge)
prometheus.MustRegister(tasksCounter)
prometheus.MustRegister(taskDuration)
}
type PoolMetrics struct {
Name string
poolName string
activeWorkers int32
completedTasks int32
queuedTasks int32
QueueLength int
queueLength int32
rejectedTasks int32
ActiveWorkers int
QueueCapacity int
CompletedTasks int
RejectedTasks int
}
func NewPoolMetrics(poolName string) *PoolMetrics {
return &PoolMetrics{poolName: poolName}
}
func (m *PoolMetrics) UpdateActiveWorkers(count int) {
workerPoolGauge.WithLabelValues(m.poolName).Set(float64(count))
}
func (m *PoolMetrics) UpdateQueueLength(length, capacity int) {
queueLengthGauge.WithLabelValues(m.poolName).Set(float64(length))
}
func (m *PoolMetrics) RecordTaskCompletion(success bool, duration time.Duration) {
result := "success"
if !success {
result = "failure"
}
tasksCounter.WithLabelValues(m.poolName, result).Add(1)
taskDuration.WithLabelValues(m.poolName).Observe(duration.Seconds())
}
func (m *PoolMetrics) RecordTaskSubmission() {
// 可以添加任务提交的指标
}
func (m *PoolMetrics) RecordTaskStarted() {
atomic.AddInt32(&m.activeWorkers, 1)
}
func (m *PoolMetrics) RecordTaskCompleted() {
atomic.AddInt32(&m.activeWorkers, -1)
atomic.AddInt32(&m.completedTasks, 1)
}
func (m *PoolMetrics) RecordTaskQueued() {
atomic.AddInt32(&m.queuedTasks, 1)
}
func (m *PoolMetrics) RecordTaskRejected() {
atomic.AddInt32(&m.rejectedTasks, 1)
}
/*
func (m *PoolMetrics) Snapshot() PoolMetrics {
return PoolMetrics{
Name: m.Name,
ActiveWorkers: int(atomic.LoadInt32(&m.activeWorkers)),
QueueLength: int(atomic.LoadInt32(&m.queuedTasks)),
QueueCapacity: m.QueueCapacity,
CompletedTasks: int(atomic.LoadInt32(&m.completedTasks)),
RejectedTasks: int(atomic.LoadInt32(&m.rejectedTasks)),
}
}
*/
func (m *PoolMetrics) Snapshot() PoolMetrics {
return PoolMetrics{
Name: m.Name,
ActiveWorkers: int(atomic.LoadInt32(&m.activeWorkers)),
QueueLength: int(atomic.LoadInt32(&m.queueLength)),
QueueCapacity: m.QueueCapacity,
CompletedTasks: int(atomic.LoadInt32(&m.completedTasks)),
RejectedTasks: int(atomic.LoadInt32(&m.rejectedTasks)),
}
}
Go
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bounded Parallelism Pattern 有界并行模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/5/29 21:56
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : gold_price.go
*/
package gold
import (
"context"
"time"
)
type GoldPrice struct {
Amount float64 // 每克价格
Currency string // 货币代码
Timestamp time.Time // 价格时间戳
Source string // 数据来源
}
type PriceClient interface {
FetchCurrentPrice(ctx context.Context) (*GoldPrice, error)
FetchHistoricalPrices(ctx context.Context, startDate, endDate time.Time) ([]*GoldPrice, error)
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bounded Parallelism Pattern 有界并行模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/5/29 21:57
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : base_calculator.go
*/
package calculator
import (
"godesginpattern/boundedparallelism/domain/order"
)
type BaseCalculator struct{}
func (c *BaseCalculator) CalculateTotalWeight(items []order.OrderItem) float64 {
var total float64
for _, item := range items {
total += item.WeightGrams
}
return total
}
func (c *BaseCalculator) CalculatePurityAdjustedWeight(items []order.OrderItem) float64 {
var total float64
for _, item := range items {
total += item.WeightGrams * item.Purity
}
return total
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bounded Parallelism Pattern 有界并行模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/5/29 21:59
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : vip_calculator.go
*/
package calculator
import "godesginpattern/boundedparallelism/domain/order"
type VIPCalculator struct {
BaseCalculator
}
func NewVIPCalculator() *VIPCalculator {
return &VIPCalculator{}
}
func (c *VIPCalculator) CalculateTotalWeight(items []order.OrderItem) float64 {
// VIP客户享受1%的重量折扣
baseWeight := c.BaseCalculator.CalculateTotalWeight(items)
return baseWeight * 0.99
}
func (c *VIPCalculator) CalculatePurityAdjustedWeight(items []order.OrderItem) float64 {
// VIP客户享受1.5%的纯度调整折扣
baseWeight := c.BaseCalculator.CalculatePurityAdjustedWeight(items)
return baseWeight * 0.985
}
func (c *VIPCalculator) ApplyVIPDiscount(total float64) float64 {
return total * 0.95 // 5%折扣
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bounded Parallelism Pattern 有界并行模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/5/29 22:01
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : order.go
*/
package order
import (
"errors"
"fmt"
"godesginpattern/boundedparallelism/domain/gold"
"math/rand"
"time"
)
var (
ErrInvalidWeight = errors.New("无效的黄金重量")
ErrInvalidPurity = errors.New("无效的黄金纯度")
ErrEmptyItems = errors.New("订单必须包含至少一个商品")
ErrUnsupportedPurity = errors.New("不支持的黄金纯度")
)
type Order struct {
ID string
CustomerID string
Items []OrderItem
IsVIP bool
Status string
CreatedAt time.Time
UpdatedAt time.Time
GoldPrice *gold.GoldPrice
}
type OrderItem struct {
ProductID string
WeightGrams float64
Purity float64
Subtotal float64
}
func NewOrder(
customerID string,
items []OrderItem,
isVIP bool,
goldPrice *gold.GoldPrice,
) (*Order, error) {
if customerID == "" {
return nil, errors.New("客户ID不能为空")
}
if len(items) == 0 {
return nil, ErrEmptyItems
}
// 验证订单项
for _, item := range items {
if item.WeightGrams <= 0 {
return nil, ErrInvalidWeight
}
if item.Purity < 0.5 || item.Purity > 1.0 {
return nil, ErrInvalidPurity
}
}
return &Order{
ID: generateOrderID(),
CustomerID: customerID,
Items: items,
IsVIP: isVIP,
Status: "PENDING",
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
GoldPrice: goldPrice,
}, nil
}
func (o *Order) CalculateTotal() (float64, error) {
var total float64
if o.GoldPrice == nil || o.GoldPrice.Amount <= 0 {
return 0, errors.New("无效的金价数据")
}
for i, item := range o.Items {
// 计算每件商品价格:重量(克) * 纯度 * 金价(每克)
subtotal := item.WeightGrams * item.Purity * o.GoldPrice.Amount
o.Items[i].Subtotal = subtotal
total += subtotal
}
// VIP客户享受95折
if o.IsVIP {
total = total * 0.95
}
// 添加10%增值税
total = total * 1.10
return total, nil
}
func (o *Order) UpdateStatus(newStatus string) error {
validStatuses := map[string]bool{
"PENDING": true,
"PROCESSING": true,
"COMPLETED": true,
"CANCELLED": true,
}
if !validStatuses[newStatus] {
return errors.New("无效的订单状态")
}
o.Status = newStatus
o.UpdatedAt = time.Now()
return nil
}
func generateOrderID() string {
// 实际生产中应使用更可靠的ID生成器
return "ORD-" + time.Now().Format("20060102") + "-" +
fmt.Sprintf("%06d", rand.Intn(999999))
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bounded Parallelism Pattern 有界并行模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/5/29 22:00
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : order_repository.go
*/
package order
import "context"
type Repository interface {
Save(ctx context.Context, order *Order) error
FindByID(ctx context.Context, id string) (*Order, error)
FindByCustomer(ctx context.Context, customerID string, limit, offset int) ([]*Order, error)
UpdateStatus(ctx context.Context, id, status string) error
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bounded Parallelism Pattern 有界并行模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/5/29 21:55
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : order_validator.go
*/
package order
import (
"errors"
//"godesginpattern/boundedparallelism/domain/order"
"regexp"
"time"
)
var (
ErrInvalidCustomerID = errors.New("无效的客户ID格式")
ErrInvalidProductID = errors.New("无效的产品ID格式")
)
type OrderValidator struct {
customerIDRegex *regexp.Regexp
productIDRegex *regexp.Regexp
}
type OrderRequest struct {
// 字段定义
ID string
CustomerID string
Items []OrderItem
Timestamp time.Time
UserID string
IsVIP bool // 添加缺失的字段
// 其他必要字段
}
func NewOrderValidator() *OrderValidator {
return &OrderValidator{
customerIDRegex: regexp.MustCompile(`^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$`),
productIDRegex: regexp.MustCompile(`^PROD-[A-Z0-9]{6}$`),
}
}
func (v *OrderValidator) Validate(req *OrderRequest) error {
// 验证客户ID格式
if !v.customerIDRegex.MatchString(req.CustomerID) {
return ErrInvalidCustomerID
}
// 验证订单项
if len(req.Items) == 0 {
return errors.New("订单必须包含至少一个商品")
}
for _, item := range req.Items {
if !v.productIDRegex.MatchString(item.ProductID) {
return ErrInvalidProductID
}
if item.WeightGrams <= 0 {
return errors.New("商品重量必须大于0")
}
if item.Purity < 0.5 || item.Purity > 1.0 {
return errors.New("黄金纯度必须在0.5到1.0之间")
}
}
return nil
}
Go
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bounded Parallelism Pattern 有界并行模式
# github.com/go-playground/validator/v10
# go get github.com/go-playground/validator/v10
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/5/29 22:12
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : order_handler.go
*/
package http
import (
"context"
"encoding/json"
"github.com/go-playground/validator/v10"
"godesginpattern/boundedparallelism/application/order"
"godesginpattern/boundedparallelism/application/order/dto"
"log"
"net/http"
"time"
)
type OrderHandler struct {
processor *order.OrderProcessor
validator *validator.Validate
}
func NewOrderHandler(processor *order.OrderProcessor) *OrderHandler {
return &OrderHandler{
processor: processor,
validator: validator.New(),
}
}
func (h *OrderHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodPost:
if r.URL.Path == "/orders" {
h.createOrder(w, r)
return
}
}
http.NotFound(w, r)
}
func (h *OrderHandler) createOrder(w http.ResponseWriter, r *http.Request) {
var req dto.CreateOrderRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
h.handleError(w, http.StatusBadRequest, "无效的请求体")
return
}
// 验证请求数据
if err := h.validator.Struct(req); err != nil {
h.handleError(w, http.StatusBadRequest, "请求数据验证失败: "+err.Error())
return
}
// 处理订单
ctx, cancel := context.WithTimeout(r.Context(), 30*time.Second)
defer cancel()
response, err := h.processor.ProcessOrder(ctx, &order.OrderRequest{
CustomerID: req.CustomerID,
Items: convertToDomainItems(req.Items),
IsVIP: req.IsVIP,
})
if err != nil {
h.handleError(w, http.StatusInternalServerError, "订单处理失败: "+err.Error())
return
}
// 转换为DTO响应
dtoResponse := dto.OrderResponseDTO{
OrderID: response.OrderID,
Total: response.Total,
Status: response.Status,
CreatedAt: response.Created,
}
// 填充订单项
for _, item := range req.Items {
dtoResponse.Items = append(dtoResponse.Items, struct {
ProductID string `json:"product_id"`
WeightGrams float64 `json:"weight_grams"`
Purity float64 `json:"purity"`
Subtotal float64 `json:"subtotal"`
}{
ProductID: item.ProductID,
WeightGrams: item.WeightGrams,
Purity: item.Purity,
Subtotal: calculateSubtotal(item, response.Total),
})
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
if err := json.NewEncoder(w).Encode(dtoResponse); err != nil {
log.Printf("响应编码失败: %v", err)
}
}
func (h *OrderHandler) handleError(w http.ResponseWriter, status int, message string) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(map[string]string{
"error": message,
})
}
func convertToDomainItems(items []dto.OrderItemDTO) []order.OrderItem {
domainItems := make([]order.OrderItem, len(items))
for i, item := range items {
domainItems[i] = order.OrderItem{
ProductID: item.ProductID,
WeightGrams: item.WeightGrams,
Purity: item.Purity,
}
}
return domainItems
}
func calculateSubtotal(item dto.OrderItemDTO, total float64) float64 {
// 简化实现,实际应基于金价计算
return item.WeightGrams * item.Purity * 60.0
}
Go
package concurrency
import (
"context"
"errors"
"godesginpattern/boundedparallelism/common/concurrency"
"godesginpattern/boundedparallelism/common/metrics"
"sync"
"time"
)
var (
ErrQueueFull = errors.New("任务队列已满")
)
type BoundedWorkerPool struct {
queue chan func()
workerPool *concurrency.BoundedExecutor
metrics *metrics.PoolMetrics
shutdownOnce sync.Once
}
func NewBoundedWorkerPool(workerCount, queueCapacity int) *BoundedWorkerPool {
pool := &BoundedWorkerPool{
queue: make(chan func(), queueCapacity),
metrics: metrics.NewPoolMetrics("bounded_worker_pool"),
workerPool: concurrency.NewBoundedExecutor(workerCount),
}
for i := 0; i < workerCount; i++ {
pool.workerPool.Submit(pool.worker)
}
return pool
}
func (p *BoundedWorkerPool) worker() {
for task := range p.queue {
p.metrics.RecordTaskStarted()
task()
p.metrics.RecordTaskCompleted()
}
}
func (p *BoundedWorkerPool) Submit(task func()) error {
select {
case p.queue <- task:
p.metrics.RecordTaskQueued()
return nil
default:
p.metrics.RecordTaskRejected()
return ErrQueueFull
}
}
func (p *BoundedWorkerPool) GetMetrics() metrics.PoolMetrics {
return p.metrics.Snapshot()
}
func (p *BoundedWorkerPool) Shutdown(ctx context.Context) error {
var err error
p.shutdownOnce.Do(func() {
close(p.queue)
shutdownCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
err = p.workerPool.Shutdown(shutdownCtx)
})
return err
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bounded Parallelism Pattern 有界并行模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/5/29 22:09
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : metrics_collector.go
*/
package concurrency
import (
"sync/atomic"
"time"
)
/**/
type PoolMetrics struct {
activeWorkers int32
queueLength int32
queueCapacity int
QueueLength int
completedTasks uint64
failedTasks uint64
totalWaitTime time.Duration
totalProcessTime time.Duration
}
func NewPoolMetrics() *PoolMetrics {
return &PoolMetrics{
queueCapacity: 0,
}
}
func (m *PoolMetrics) RecordTaskQueued() {
atomic.AddInt32(&m.queueLength, 1)
}
func (m *PoolMetrics) RecordTaskDequeued() {
atomic.AddInt32(&m.queueLength, -1)
}
func (m *PoolMetrics) UpdateQueueLength(length int) {
m.QueueLength = length // 使用 QueueLength 而非 queueLength
}
func (m *PoolMetrics) RecordTaskStarted() {
atomic.AddInt32(&m.activeWorkers, 1)
}
func (m *PoolMetrics) RecordTaskCompleted(processTime time.Duration) {
atomic.AddInt32(&m.activeWorkers, -1)
atomic.AddUint64(&m.completedTasks, 1)
atomic.AddInt64((*int64)(&m.totalProcessTime), int64(processTime))
}
func (m *PoolMetrics) RecordTaskRejected() {
atomic.AddUint64(&m.failedTasks, 1)
}
func (m *PoolMetrics) RecordWaitTime(waitTime time.Duration) {
atomic.AddInt64((*int64)(&m.totalWaitTime), int64(waitTime))
}
func (m *PoolMetrics) Snapshot() PoolMetricsSnapshot {
return PoolMetricsSnapshot{
ActiveWorkers: int(atomic.LoadInt32(&m.activeWorkers)),
QueueLength: int(atomic.LoadInt32(&m.queueLength)),
QueueCapacity: m.queueCapacity,
CompletedTasks: atomic.LoadUint64(&m.completedTasks),
FailedTasks: atomic.LoadUint64(&m.failedTasks),
TotalWaitTime: m.totalWaitTime,
TotalProcessTime: m.totalProcessTime,
}
}
type PoolMetricsSnapshot struct {
ActiveWorkers int
QueueLength int
QueueCapacity int
CompletedTasks uint64
FailedTasks uint64
TotalWaitTime time.Duration
TotalProcessTime time.Duration
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bounded Parallelism Pattern 有界并行模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/5/29 22:09
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : priority_queue.go
*/
package concurrency
import (
"container/heap"
"sync"
"time"
)
type Priority int
const (
LowPriority Priority = iota
MediumPriority
HighPriority
)
type Task struct {
Priority Priority
SubmitTime int64
ExecuteFunc func()
}
type PriorityQueue struct {
items []*Task
mu sync.Mutex
}
func (pq *PriorityQueue) Len() int { return len(pq.items) }
func (pq *PriorityQueue) Less(i, j int) bool {
// 高优先级先执行,同优先级按提交时间排序
if pq.items[i].Priority == pq.items[j].Priority {
return pq.items[i].SubmitTime < pq.items[j].SubmitTime
}
return pq.items[i].Priority > pq.items[j].Priority
}
func (pq *PriorityQueue) Swap(i, j int) {
pq.items[i], pq.items[j] = pq.items[j], pq.items[i]
}
func (pq *PriorityQueue) Push(x interface{}) {
item := x.(*Task)
pq.items = append(pq.items, item)
}
func (pq *PriorityQueue) Pop() interface{} {
old := pq.items
n := len(old)
item := old[n-1]
old[n-1] = nil
pq.items = old[0 : n-1]
return item
}
func (pq *PriorityQueue) Enqueue(task *Task) {
pq.mu.Lock()
defer pq.mu.Unlock()
task.SubmitTime = time.Now().UnixNano()
heap.Push(pq, task)
}
func (pq *PriorityQueue) Dequeue() *Task {
pq.mu.Lock()
defer pq.mu.Unlock()
if pq.Len() == 0 {
return nil
}
return heap.Pop(pq).(*Task)
}
func (pq *PriorityQueue) Peek() *Task {
pq.mu.Lock()
defer pq.mu.Unlock()
if pq.Len() == 0 {
return nil
}
return pq.items[0]
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bounded Parallelism Pattern 有界并行模式
# github.com/joho/godotenv
# go get github.com/joho/godotenv
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/5/29 22:10
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : config_loader.go
*/
package config
import (
"github.com/joho/godotenv"
"os"
"strconv"
)
type Config struct {
ServerAddress string
DatabaseURL string
GoldAPIKey string
GoldAPIEndpoint string
WorkerPoolSize int
QueueCapacity int
}
func LoadConfig() (*Config, error) {
// 尝试加载 .env 文件(仅在开发环境)
_ = godotenv.Load()
workerPoolSize, _ := strconv.Atoi(getEnv("WORKER_POOL_SIZE", "10"))
queueCapacity, _ := strconv.Atoi(getEnv("QUEUE_CAPACITY", "100"))
return &Config{
ServerAddress: getEnv("SERVER_ADDRESS", ":8082"),
DatabaseURL: getEnv("DATABASE_URL", "postgres://postgres:geovindu@localhost:5432/jewelry?sslmode=disable"),
GoldAPIKey: getEnv("GOLD_API_KEY", ""),
GoldAPIEndpoint: getEnv("GOLD_API_ENDPOINT", ""),
WorkerPoolSize: workerPoolSize,
QueueCapacity: queueCapacity,
}, nil
}
func getEnv(key, defaultValue string) string {
if value, exists := os.LookupEnv(key); exists {
return value
}
return defaultValue
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bounded Parallelism Pattern 有界并行模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/5/29 22:09
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : lbma_client.go
*/
package goldprice
import (
"context"
"encoding/json"
"errors"
"fmt"
"godesginpattern/boundedparallelism/domain/gold"
"net/http"
"time"
)
const (
lbmaAPIEndpoint = "https://www.lbma.org.uk/json-prices/current"
timeout = 10 * time.Second
)
type LBMAClient struct {
apiKey string
endpoint string
httpClient *http.Client
}
func NewLBMAClient(apiKey, endpoint string) *LBMAClient {
if endpoint == "" {
endpoint = lbmaAPIEndpoint
}
return &LBMAClient{
apiKey: apiKey,
endpoint: endpoint,
httpClient: &http.Client{
Timeout: timeout,
},
}
}
type lbmaResponse struct {
USD []struct {
Currency string `json:"currency"`
Amount float64 `json:"price"`
Unit string `json:"unitcode"`
DateTime string `json:"datetime"`
} `json:"usd"`
}
func (c *LBMAClient) FetchCurrentPrice(ctx context.Context) (*gold.GoldPrice, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.endpoint, nil)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", "Bearer "+c.apiKey)
req.Header.Set("Accept", "application/json")
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("LBMA API返回错误状态码: %d", resp.StatusCode)
}
var data lbmaResponse
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
return nil, err
}
if len(data.USD) == 0 {
return nil, errors.New("LBMA API返回空数据")
}
// LBMA通常返回每盎司价格,需要转换为每克价格
// 1盎司 = 31.1035克
pricePerGram := data.USD[0].Amount / 31.1035
timestamp, err := time.Parse("2006-01-02T15:04:05", data.USD[0].DateTime)
if err != nil {
timestamp = time.Now()
}
return &gold.GoldPrice{
Amount: pricePerGram,
Currency: "USD",
Timestamp: timestamp,
Source: "LBMA",
}, nil
}
func (c *LBMAClient) FetchHistoricalPrices(ctx context.Context, startDate, endDate time.Time) ([]*gold.GoldPrice, error) {
// 实际实现应调用LBMA的历史数据API
// 这里简化实现只返回错误
return nil, errors.New("历史数据查询功能尚未实现")
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bounded Parallelism Pattern 有界并行模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/5/29 22:10
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : mock_client.go
*/
package goldprice
import (
"context"
"godesginpattern/boundedparallelism/domain/gold"
"time"
)
type MockClient struct {
currentPrice *gold.GoldPrice
history []*gold.GoldPrice
}
func NewMockClient(currentPrice float64) *MockClient {
now := time.Now()
return &MockClient{
currentPrice: &gold.GoldPrice{
Amount: currentPrice,
Currency: "USD",
Timestamp: now,
Source: "MOCK",
},
history: []*gold.GoldPrice{
{
Amount: currentPrice - 5.0,
Currency: "USD",
Timestamp: now.Add(-24 * time.Hour),
Source: "MOCK",
},
{
Amount: currentPrice - 2.5,
Currency: "USD",
Timestamp: now.Add(-12 * time.Hour),
Source: "MOCK",
},
{
Amount: currentPrice,
Currency: "USD",
Timestamp: now,
Source: "MOCK",
},
},
}
}
func (m *MockClient) FetchCurrentPrice(ctx context.Context) (*gold.GoldPrice, error) {
return m.currentPrice, nil
}
func (m *MockClient) FetchHistoricalPrices(ctx context.Context, startDate, endDate time.Time) ([]*gold.GoldPrice, error) {
var result []*gold.GoldPrice
for _, price := range m.history {
if !price.Timestamp.Before(startDate) && !price.Timestamp.After(endDate) {
result = append(result, price)
}
}
return result, nil
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bounded Parallelism Pattern 有界并行模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/5/29 22:09
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : db.go
*/
package persistence
import (
"database/sql"
_ "github.com/lib/pq"
)
func NewDBConnection(databaseURL string) (*sql.DB, error) {
db, err := sql.Open("postgres", databaseURL)
if err != nil {
return nil, err
}
if err := db.Ping(); err != nil {
return nil, err
}
return db, nil
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bounded Parallelism Pattern 有界并行模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/5/29 22:10
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : order_repository.go
*/
package persistence
import (
"context"
"database/sql"
"errors"
"fmt"
"godesginpattern/boundedparallelism/domain/gold"
"godesginpattern/boundedparallelism/domain/order"
"time"
)
var (
ErrOrderNotFound = errors.New("订单未找到")
)
type OrderRepository struct {
db *sql.DB
}
func NewOrderRepository(db *sql.DB) *OrderRepository {
return &OrderRepository{db: db}
}
func (r *OrderRepository) Save(ctx context.Context, o *order.Order) error {
tx, err := r.db.BeginTx(ctx, nil)
if err != nil {
return err
}
defer tx.Rollback()
// 保存主订单
_, err = tx.ExecContext(ctx,
`INSERT INTO orders (id, customer_id, status, created_at, updated_at, gold_price, currency)
VALUES ($1, $2, $3, $4, $5, $6, $7)
ON CONFLICT (id) DO UPDATE
SET status = $3, updated_at = $5, gold_price = $6, currency = $7`,
o.ID,
o.CustomerID,
o.Status,
o.CreatedAt,
o.UpdatedAt,
o.GoldPrice.Amount,
o.GoldPrice.Currency,
)
if err != nil {
return fmt.Errorf("保存订单失败: %w", err)
}
// 删除旧的订单项
_, err = tx.ExecContext(ctx,
`DELETE FROM order_items WHERE order_id = $1`,
o.ID,
)
if err != nil {
return fmt.Errorf("清理订单项失败: %w", err)
}
// 保存新的订单项
for _, item := range o.Items {
_, err = tx.ExecContext(ctx,
`INSERT INTO order_items (order_id, product_id, weight_grams, purity, subtotal)
VALUES ($1, $2, $3, $4, $5)`,
o.ID,
item.ProductID,
item.WeightGrams,
item.Purity,
item.Subtotal,
)
if err != nil {
return fmt.Errorf("保存订单项失败: %w", err)
}
}
return tx.Commit()
}
func (r *OrderRepository) FindByID(ctx context.Context, id string) (*order.Order, error) {
var o order.Order
var goldPrice float64
var currency string
var createdAt, updatedAt time.Time
err := r.db.QueryRowContext(ctx,
`SELECT id, customer_id, status, created_at, updated_at, gold_price, currency
FROM orders WHERE id = $1`,
id,
).Scan(
&o.ID,
&o.CustomerID,
&o.Status,
&createdAt,
&updatedAt,
&goldPrice,
¤cy,
)
if err == sql.ErrNoRows {
return nil, ErrOrderNotFound
}
if err != nil {
return nil, fmt.Errorf("查询订单失败: %w", err)
}
o.CreatedAt = createdAt
o.UpdatedAt = updatedAt
o.GoldPrice = &gold.GoldPrice{
Amount: goldPrice,
Currency: currency,
}
// 查询订单项
rows, err := r.db.QueryContext(ctx,
`SELECT product_id, weight_grams, purity, subtotal
FROM order_items WHERE order_id = $1`,
id,
)
if err != nil {
return nil, fmt.Errorf("查询订单项失败: %w", err)
}
defer rows.Close()
for rows.Next() {
var item order.OrderItem
if err := rows.Scan(
&item.ProductID,
&item.WeightGrams,
&item.Purity,
&item.Subtotal,
); err != nil {
return nil, fmt.Errorf("解析订单项失败: %w", err)
}
o.Items = append(o.Items, item)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("遍历订单项失败: %w", err)
}
return &o, nil
}
func (r *OrderRepository) FindByCustomer(ctx context.Context, customerID string, limit, offset int) ([]*order.Order, error) {
rows, err := r.db.QueryContext(ctx,
`SELECT id, customer_id, status, created_at, updated_at, gold_price, currency
FROM orders WHERE customer_id = $1
ORDER BY created_at DESC
LIMIT $2 OFFSET $3`,
customerID, limit, offset,
)
if err != nil {
return nil, fmt.Errorf("查询客户订单失败: %w", err)
}
defer rows.Close()
var orders []*order.Order
for rows.Next() {
var o order.Order
var goldPrice float64
var currency string
var createdAt, updatedAt time.Time
if err := rows.Scan(
&o.ID,
&o.CustomerID,
&o.Status,
&createdAt,
&updatedAt,
&goldPrice,
¤cy,
); err != nil {
return nil, fmt.Errorf("解析订单失败: %w", err)
}
o.CreatedAt = createdAt
o.UpdatedAt = updatedAt
o.GoldPrice = &gold.GoldPrice{
Amount: goldPrice,
Currency: currency,
}
// 查询订单项
items, err := r.loadOrderItems(ctx, o.ID)
if err != nil {
return nil, err
}
o.Items = items
orders = append(orders, &o)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("遍历订单结果失败: %w", err)
}
return orders, nil
}
func (r *OrderRepository) loadOrderItems(ctx context.Context, orderID string) ([]order.OrderItem, error) {
rows, err := r.db.QueryContext(ctx,
`SELECT product_id, weight_grams, purity, subtotal
FROM order_items WHERE order_id = $1`,
orderID,
)
if err != nil {
return nil, fmt.Errorf("查询订单项失败: %w", err)
}
defer rows.Close()
var items []order.OrderItem
for rows.Next() {
var item order.OrderItem
if err := rows.Scan(
&item.ProductID,
&item.WeightGrams,
&item.Purity,
&item.Subtotal,
); err != nil {
return nil, fmt.Errorf("解析订单项失败: %w", err)
}
items = append(items, item)
}
return items, rows.Err()
}
func (r *OrderRepository) UpdateStatus(ctx context.Context, id, status string) error {
result, err := r.db.ExecContext(ctx,
`UPDATE orders SET status = $1, updated_at = $2 WHERE id = $3`,
status,
time.Now(),
id,
)
if err != nil {
return fmt.Errorf("更新订单状态失败: %w", err)
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return fmt.Errorf("获取受影响行数失败: %w", err)
}
if rowsAffected == 0 {
return ErrOrderNotFound
}
return nil
}
Go
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bounded Parallelism Pattern 有界并行模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/5/29 22:19
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : price_service.go
*/
package gold
import (
"context"
"errors"
"godesginpattern/boundedparallelism/domain/gold"
"time"
)
var (
ErrPriceServiceUnavailable = "金价服务暂时不可用"
ErrInvalidPriceData = errors.New("无效的金价数据")
)
type PriceService interface {
GetCurrentPrice(ctx context.Context) (*gold.GoldPrice, error)
GetHistoricalPrices(ctx context.Context, startDate, endDate time.Time) ([]*gold.GoldPrice, error)
}
type GoldPriceService struct {
client gold.PriceClient
}
func NewGoldPriceService(client gold.PriceClient) *GoldPriceService {
return &GoldPriceService{
client: client,
}
}
func (s *GoldPriceService) GetCurrentPrice(ctx context.Context) (*gold.GoldPrice, error) {
price, err := s.client.FetchCurrentPrice(ctx)
if err != nil {
return nil, err
}
// 验证价格数据有效性
if price.Amount <= 0 || price.Currency != "USD" || price.Timestamp.IsZero() {
return nil, ErrInvalidPriceData
}
return price, nil
}
func (s *GoldPriceService) GetHistoricalPrices(ctx context.Context, startDate, endDate time.Time) ([]*gold.GoldPrice, error) {
if endDate.Before(startDate) {
return nil, errors.New("结束日期不能早于开始日期")
}
// 限制查询范围不超过30天
if endDate.Sub(startDate) > 30*24*time.Hour {
return nil, errors.New("历史价格查询范围不能超过30天")
}
return s.client.FetchHistoricalPrices(ctx, startDate, endDate)
}
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bounded Parallelism Pattern 有界并行模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/5/29 22:18
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : order_request.go
*/
package dto
import "time"
type CreateOrderRequest struct {
CustomerID string `json:"customer_id" validate:"required,uuid4"`
Items []OrderItemDTO `json:"items" validate:"required,min=1,dive"`
IsVIP bool `json:"is_vip"`
}
type OrderItemDTO struct {
ProductID string `json:"product_id" validate:"required"`
WeightGrams float64 `json:"weight_grams" validate:"gt=0"`
Purity float64 `json:"purity" validate:"min=0.5,max=1.0"`
}
type OrderResponseDTO struct {
OrderID string `json:"order_id"`
Total float64 `json:"total"`
Status string `json:"status"`
CreatedAt time.Time `json:"created_at"`
Items []struct {
ProductID string `json:"product_id"`
WeightGrams float64 `json:"weight_grams"`
Purity float64 `json:"purity"`
Subtotal float64 `json:"subtotal"`
} `json:"items"`
}
type OrderRequest struct {
UserID string
Items []OrderItem
Timestamp time.Time
IsVIP bool // 确保包含此字段
}
type OrderItem struct {
ProductID string
Quantity int
Price float64
}
package order
import (
"context"
"errors"
"godesginpattern/boundedparallelism/application/gold"
domainorder "godesginpattern/boundedparallelism/domain/order"
"godesginpattern/boundedparallelism/infrastructure/concurrency"
"time"
)
var (
ErrInvalidOrder = errors.New("无效的订单数据")
ErrProcessingFailed = errors.New("订单处理失败")
ErrConcurrencyLimit = errors.New("并发处理已达上限")
ErrGoldPriceUnavailable = errors.New("金价数据不可用")
)
type OrderProcessor struct {
repo domainorder.Repository
priceService gold.PriceService
validator *domainorder.OrderValidator
workerPool *concurrency.BoundedWorkerPool
}
func NewOrderProcessor(
repo domainorder.Repository,
priceService gold.PriceService,
validator *domainorder.OrderValidator,
workerPool *concurrency.BoundedWorkerPool,
) *OrderProcessor {
return &OrderProcessor{
repo: repo,
priceService: priceService,
validator: validator,
workerPool: workerPool,
}
}
func (p *OrderProcessor) ProcessOrder(ctx context.Context, req *OrderRequest) (*OrderResponse, error) {
if err := p.validator.Validate(&domainorder.OrderRequest{
CustomerID: req.CustomerID,
Items: convertToDomainItems(req.Items),
IsVIP: req.IsVIP,
}); err != nil {
return nil, ErrInvalidOrder
}
goldPrice, err := p.priceService.GetCurrentPrice(ctx)
if err != nil {
return nil, ErrGoldPriceUnavailable
}
domainItems := convertToDomainItems(req.Items)
domainOrder, err := domainorder.NewOrder(
req.CustomerID,
domainItems,
req.IsVIP,
goldPrice,
)
if err != nil {
return nil, ErrInvalidOrder
}
resultChan := make(chan *OrderProcessingResult, 1)
err = p.workerPool.Submit(func() {
if err := p.repo.Save(ctx, domainOrder); err != nil {
resultChan <- &OrderProcessingResult{Err: err}
return
}
total, err := domainOrder.CalculateTotal()
if err != nil {
resultChan <- &OrderProcessingResult{Err: err}
return
}
resultChan <- &OrderProcessingResult{
OrderID: domainOrder.ID,
Total: total,
Status: domainOrder.Status,
}
})
if err != nil {
return nil, ErrConcurrencyLimit
}
select {
case result := <-resultChan:
if result.Err != nil {
return nil, ErrProcessingFailed
}
return &OrderResponse{
OrderID: result.OrderID,
Total: result.Total,
Status: result.Status,
Created: time.Now(),
}, nil
case <-ctx.Done():
return nil, ctx.Err()
}
}
func convertToDomainItems(items []OrderItem) []domainorder.OrderItem {
domainItems := make([]domainorder.OrderItem, len(items))
for i, item := range items {
domainItems[i] = domainorder.OrderItem{
ProductID: item.ProductID,
WeightGrams: item.WeightGrams,
Purity: item.Purity,
}
}
return domainItems
}
type OrderRequest struct {
CustomerID string
Items []OrderItem
IsVIP bool
}
type OrderItem struct {
ProductID string
WeightGrams float64
Purity float64
}
type OrderResponse struct {
OrderID string
Total float64
Status string
Created time.Time
}
type OrderProcessingResult struct {
OrderID string
Total float64
Status string
Err error
}
调用:
Go
/*
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Bounded Parallelism Pattern 有界并行模式
# Author : geovindu,Geovin Du 涂聚文.
# IDE : goLang 2024.3.6 go 26.2
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/5/29 22:13
# User : geovindu
# Product : GoLand
# Project : godesginpattern
# File : boundedparallelismbll.go
*/
package bll
import (
"context"
"godesginpattern/boundedparallelism/application/gold"
"godesginpattern/boundedparallelism/application/order"
domainorder "godesginpattern/boundedparallelism/domain/order"
"godesginpattern/boundedparallelism/infrastructure/concurrency"
"godesginpattern/boundedparallelism/infrastructure/config"
"godesginpattern/boundedparallelism/infrastructure/goldprice"
"godesginpattern/boundedparallelism/infrastructure/persistence"
httpapi "godesginpattern/boundedparallelism/interfaces/http"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func BoundedparallelismMain() {
log.Println("步骤1: 加载配置")
cfg, err := config.LoadConfig()
if err != nil {
log.Fatalf("无法加载配置: %v", err)
}
log.Printf("配置加载成功: ServerAddress=%s", cfg.ServerAddress)
log.Println("步骤2: 连接数据库")
db, err := persistence.NewDBConnection(cfg.DatabaseURL)
if err != nil {
log.Fatalf("无法连接数据库: %v", err)
}
defer db.Close()
log.Println("数据库连接成功")
log.Println("步骤3: 创建仓库和客户端")
orderRepo := persistence.NewOrderRepository(db)
// 使用Mock客户端(用于测试)
log.Println("使用Mock金价客户端进行测试")
goldClient := goldprice.NewMockClient(60.0) // 60美元/克
log.Println("仓库和客户端创建成功")
log.Println("步骤4: 创建服务")
priceService := gold.NewGoldPriceService(goldClient)
orderValidator := domainorder.NewOrderValidator()
log.Println("服务创建成功")
log.Println("步骤5: 创建订单处理器")
orderProcessor := order.NewOrderProcessor(
orderRepo,
priceService,
orderValidator,
concurrency.NewBoundedWorkerPool(cfg.WorkerPoolSize, cfg.QueueCapacity),
)
log.Println("订单处理器创建成功")
log.Println("步骤6: 创建HTTP处理器和服务器")
handler := httpapi.NewOrderHandler(orderProcessor)
server := &http.Server{
Addr: cfg.ServerAddress,
Handler: handler,
ReadTimeout: 15 * time.Second,
WriteTimeout: 15 * time.Second,
}
log.Println("HTTP服务器创建成功")
log.Println("步骤7: 启动HTTP服务器...")
go func() {
log.Printf("订单处理器服务已启动,监听地址: %s", cfg.ServerAddress)
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("服务器启动失败: %v", err)
}
}()
log.Println("步骤8: 等待关闭信号")
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
log.Println("关闭服务器...")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
log.Fatalf("服务器强制关闭: %v", err)
}
log.Println("服务器已成功关闭")
}
输出:
