package syncx import ( "io" "sync" ) type ResourceManager struct { resource map[string]io.Closer singleFlight SingleFlight lock sync.Mutex } func NewResourceManager() *ResourceManager { return &ResourceManager{ resource: make(map[string]io.Closer), singleFlight: NewSingleFlight(), } } func (manager *ResourceManager) Close() error { manager.lock.Lock() defer manager.lock.Unlock() var be errorx.BatchError for _, resource := range manager.resource { if err := resource.Close(); err != nil { be.Add(err) } } manager.resource = nil return be.Err() } func (manager *ResourceManager) GetResource(key string, create func() (io.Closer, error)) (io.Closer, error) { val, err := manager.singleFlight.Do(key, func() (any, error) { manager.lock.Lock() resource, ok := manager.resource[key] manager.lock.Unlock() if ok { return resource, nil } resource, err := create() if err != nil { return nil, err } manager.lock.Lock() defer manager.lock.Unlock() manager.resource[key] = resource return resource, nil }) if err != nil { return nil, err } return val.(io.Closer), nil } func (manager *ResourceManager) Inject(key string, resource io.Closer) { manager.lock.Lock() manager.resource[key] = resource manager.lock.Unlock() }