package dbsync import ( "database/sql" "fmt" "strings" "sync" "time" ) // remotePool 复用线上 A 连接,避免每次 push 冷开 SQLite(Windows 上常 >3s → 旧默认超时 503)。 type remotePool struct { mu sync.Mutex dbs map[string]*pooledDB } type pooledDB struct { db *sql.DB driver Driver lastUsed time.Time } var sharedRemotePool = &remotePool{dbs: map[string]*pooledDB{}} func poolKey(driver Driver, dsn string) string { if driver == DriverSQLite { dsn = normalizeSQLiteDSN(dsn) } return string(driver) + "|" + dsn } // AcquireRemote 获取(或新建)remote 连接;调用方不要 Close。 func AcquireRemote(driver Driver, dsn string) (*sql.DB, error) { return sharedRemotePool.acquire(driver, dsn) } func (p *remotePool) acquire(driver Driver, dsn string) (*sql.DB, error) { key := poolKey(driver, dsn) p.mu.Lock() defer p.mu.Unlock() if e, ok := p.dbs[key]; ok && e.db != nil { if err := e.db.Ping(); err == nil { e.lastUsed = time.Now() return e.db, nil } _ = e.db.Close() delete(p.dbs, key) } db, err := Open(driver, dsn) if err != nil { return nil, err } p.dbs[key] = &pooledDB{db: db, driver: driver, lastUsed: time.Now()} return db, nil } // WarmRemote 通道启动时预热,把冷开成本挪出请求路径。 func WarmRemote(driver Driver, dsn string) error { if strings.TrimSpace(dsn) == "" { return fmt.Errorf("dsn required") } _, err := AcquireRemote(driver, dsn) return err } // InvalidateRemote 通道 DSN 变更或停用时丢掉缓存连接。 func InvalidateRemote(driver Driver, dsn string) { key := poolKey(driver, dsn) sharedRemotePool.mu.Lock() defer sharedRemotePool.mu.Unlock() if e, ok := sharedRemotePool.dbs[key]; ok { _ = e.db.Close() delete(sharedRemotePool.dbs, key) } } // CloseAllRemotes 测试或进程退出时关闭池内连接。 func CloseAllRemotes() { sharedRemotePool.mu.Lock() defer sharedRemotePool.mu.Unlock() for k, e := range sharedRemotePool.dbs { _ = e.db.Close() delete(sharedRemotePool.dbs, k) } }