Use golang.org/x/sync/semaphore to create a weighted semaphore that limits concurrent operations. Import the package, create a new semaphore with NewWeighted, and call Acquire before your critical section and Release after.
import "golang.org/x/sync/semaphore"
sem := semaphore.NewWeighted(3)
if err := sem.Acquire(context.Background(), 1); err != nil {
// handle error
}
defer sem.Release(1)
// critical section