feat(outbound): 外发投递多线程化(worker 池 + 每域并发上限)
- 1 个 dispatcher + N 个 worker 池(默认 4)并行投递,启动时立即 扫描清空积压;workers=0/1 退化为串行(旧行为) - 每收件域并发信号量(默认 2,配置 max_concurrent_per_domain), 防对单个 MX 域并发过多被判定滥发;中继模式统一按 relay 限制 - store 新增 Claim 原子抢占(sending 状态防重复投递),并发下 每封邮件恰好投递一次 - 新增配置 workers/batch_size(替代硬编码 50);dispatcher 改为 抢占后投递、worker 只负责发送,退避重试/退信/状态机不变 - 新增测试:真并发、串行回退、每域上限、临时/永久失败、错误隔离、 Claim 并发原子性与状态可抢占性;-race 无警告
This commit is contained in:
+31
-10
@@ -126,6 +126,15 @@ type OutboundConfig struct {
|
||||
MaxPerDay int `toml:"max_per_day"` // 每用户每日最大外发数,0 表示禁用外部投递
|
||||
ConnectTimeout int `toml:"connect_timeout"` // 连接远程 MX 超时(秒)
|
||||
|
||||
// Workers 并发投递 worker 数:多 goroutine 并行发送队列中的邮件。
|
||||
// 0 或 1 表示串行(旧行为)。
|
||||
Workers int `toml:"workers"`
|
||||
// BatchSize 每次扫描最多取出的待投递邮件数。
|
||||
BatchSize int `toml:"batch_size"`
|
||||
// MaxConcurrentPerDomain 同一收件域(或中继)的最大并发连接数,
|
||||
// 防止对单个 MX 域并发过多而被判定为滥发;0 表示不限制。
|
||||
MaxConcurrentPerDomain int `toml:"max_concurrent_per_domain"`
|
||||
|
||||
// Smarthost relay: when relay_host is non-empty, all external mail is
|
||||
// delivered through this relay instead of direct MX delivery. Useful when
|
||||
// the server IP is listed in PBL/blocklists (residential/dynamic IPs).
|
||||
@@ -230,16 +239,19 @@ func defaultConfig() *Config {
|
||||
// Caddy: 留空则自动探测常见数据目录,无需配置
|
||||
Caddy: CaddyConfig{},
|
||||
Outbound: OutboundConfig{
|
||||
PollInterval: 15, // 15 秒扫描一次队列
|
||||
MaxAttempts: 12, // 最多尝试 12 次
|
||||
RetryBaseMin: 5, // 5/10/20/40/... 分钟指数退避
|
||||
MaxRecipients: 50, // 单封最多 50 个外部收件人
|
||||
MaxPerMin: 30, // 每用户每分钟 30 封
|
||||
MaxPerDay: 500,
|
||||
ConnectTimeout: 30, // 连接远程 MX 超时 30 秒
|
||||
RelayPort: 587, // smarthost 默认提交端口
|
||||
RelayStartTLS: true,
|
||||
IPFamily: "ipv4",
|
||||
PollInterval: 15, // 15 秒扫描一次队列
|
||||
MaxAttempts: 12, // 最多尝试 12 次
|
||||
RetryBaseMin: 5, // 5/10/20/40/... 分钟指数退避
|
||||
MaxRecipients: 50, // 单封最多 50 个外部收件人
|
||||
MaxPerMin: 30, // 每用户每分钟 30 封
|
||||
MaxPerDay: 500,
|
||||
ConnectTimeout: 30, // 连接远程 MX 超时 30 秒
|
||||
RelayPort: 587, // smarthost 默认提交端口
|
||||
RelayStartTLS: true,
|
||||
IPFamily: "ipv4",
|
||||
Workers: DefaultOutboundWorkers,
|
||||
BatchSize: DefaultOutboundBatchSize,
|
||||
MaxConcurrentPerDomain: DefaultMaxConcurrentPerDomain,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -325,6 +337,15 @@ func mergeDefaults(cfg *Config, defaults *Config) *Config {
|
||||
if cfg.Outbound.ConnectTimeout == 0 {
|
||||
cfg.Outbound.ConnectTimeout = defaults.Outbound.ConnectTimeout
|
||||
}
|
||||
if cfg.Outbound.Workers == 0 {
|
||||
cfg.Outbound.Workers = defaults.Outbound.Workers
|
||||
}
|
||||
if cfg.Outbound.BatchSize == 0 {
|
||||
cfg.Outbound.BatchSize = defaults.Outbound.BatchSize
|
||||
}
|
||||
if cfg.Outbound.MaxConcurrentPerDomain == 0 {
|
||||
cfg.Outbound.MaxConcurrentPerDomain = defaults.Outbound.MaxConcurrentPerDomain
|
||||
}
|
||||
if cfg.Outbound.RelayPort == 0 {
|
||||
cfg.Outbound.RelayPort = defaults.Outbound.RelayPort
|
||||
}
|
||||
|
||||
@@ -39,5 +39,15 @@ const (
|
||||
// DefaultProtocolLogKeepDays 是 SMTP/IMAP/POP3 协议调用日志的默认保留天数。
|
||||
const DefaultProtocolLogKeepDays = 30
|
||||
|
||||
// Outbound delivery concurrency defaults.
|
||||
const (
|
||||
// DefaultOutboundWorkers 并发投递 worker 数(0/1 为串行)。
|
||||
DefaultOutboundWorkers = 4
|
||||
// DefaultOutboundBatchSize 每次扫描最多取出的待投递邮件数。
|
||||
DefaultOutboundBatchSize = 50
|
||||
// DefaultMaxConcurrentPerDomain 同一收件域的最大并发连接数。
|
||||
DefaultMaxConcurrentPerDomain = 2
|
||||
)
|
||||
|
||||
// ConfigFileName is the name of the configuration file
|
||||
const ConfigFileName = "mail_go.toml"
|
||||
Reference in New Issue
Block a user