46 lines
1.2 KiB
Go
46 lines
1.2 KiB
Go
package common
|
||
|
||
import "context"
|
||
|
||
// serialWriter 单写者执行器:所有 SQLite 写链路(含「查订单→算 expiresAt→更新订单→写 license→
|
||
// 清缓存」等读改写事务)排入同一 goroutine 串行执行,规避无 WAL 时并发写 "database is locked";
|
||
// 任务结果经 buffered channel 回调用方,不额外开池(写路径天然无并行点)。
|
||
type serialWriter struct {
|
||
jobs chan func()
|
||
}
|
||
|
||
var serial = &serialWriter{jobs: make(chan func(), 64)}
|
||
|
||
func init() {
|
||
go func() {
|
||
for f := range serial.jobs {
|
||
f()
|
||
}
|
||
}()
|
||
}
|
||
|
||
// Serial 返回进程级单写者:SQLite 写操作必须经此串行执行。
|
||
func Serial() *serialWriter {
|
||
return serial
|
||
}
|
||
|
||
// Submit 排队执行写任务并等待结果,返回任务的 error;ctx 取消/超时不再等待。
|
||
// 已排队未执行的任务在 ctx 取消后仍会执行(结果入 buffered channel 无泄漏),
|
||
// 调用方以返回的 ctx.Err() 为准不再消费其结果。
|
||
func (w *serialWriter) Submit(ctx context.Context, fn func() error) error {
|
||
res := make(chan error, 1)
|
||
select {
|
||
case w.jobs <- func() {
|
||
res <- fn()
|
||
}:
|
||
case <-ctx.Done():
|
||
return ctx.Err()
|
||
}
|
||
select {
|
||
case err := <-res:
|
||
return err
|
||
case <-ctx.Done():
|
||
return ctx.Err()
|
||
}
|
||
}
|