package semaphore import ( "errors" "time" ) var ( ErrNoTickets = errors.New("semaphore: could not aquire semaphore") ErrIllegalRelease = errors.New("semaphore: can't release the semaphore without acquiring it first") ) // Interface contains the behavior of a semaphore that can be acquired and/or released. type Interface interface { Acquire() error Release() error } type implementation struct { sem chan struct{} timeout time.Duration } func (s *implementation) Acquire() error { select { case s.sem <- struct{}{}: return nil case <-time.After(s.timeout): return ErrNoTickets } } func (s *implementation) Release() error { select { case _ = <-s.sem: return nil case <-time.After(s.timeout): return ErrIllegalRelease } return nil } func New(tickets int, timeout time.Duration) Interface { return &implementation{ sem: make(chan struct{}, tickets), timeout: timeout, } }