Package semaphore implements a simple semaphore that is based on
golang.org/x/sync/semaphore but doesn't support weights. It's advantage over
a simple buffered chan is that the capacity of the semaphore (i.e. the number
of slots available) can be changed dynamically at runtime without waiting for
all existing work to stop. This makes it easier to implement e.g. concurrency
limits on certain operations that can be reconfigured at runtime.
NewDynamic returns a dynamic semaphore with the given initial capacity. Note
that this is for convenience and to match golang.org/x/sync/semaphore however
it's possible to use a zero-value semaphore provided SetSize is called before
use.
Acquire attempts to acquire one "slot" in the semaphore, blocking only until
ctx is Done. On success, returns nil. On failure, returns ctx.Err() and leaves
the semaphore unchanged.
If ctx is already done, Acquire may still succeed without blocking.
SetSize dynamically updates the number of available slots. If there are more
than n slots currently acquired, no further acquires will succeed until
sufficient have been released to take the total outstanding below n again.