github.com/anycable/anycable-go@v1.5.1/rpc/barrier.go (about)

     1  package rpc
     2  
     3  import (
     4  	"fmt"
     5  )
     6  
     7  type Barrier interface {
     8  	Acquire()
     9  	Release()
    10  	BusyCount() int
    11  	Capacity() int
    12  	CapacityInfo() string
    13  	Exhausted()
    14  	HasDynamicCapacity() bool
    15  	Start()
    16  	Stop()
    17  }
    18  
    19  type FixedSizeBarrier struct {
    20  	capacity     int
    21  	capacityInfo string
    22  	sem          chan (struct{})
    23  }
    24  
    25  var _ Barrier = (*FixedSizeBarrier)(nil)
    26  
    27  func NewFixedSizeBarrier(capacity int) (*FixedSizeBarrier, error) {
    28  	if capacity <= 0 {
    29  		return nil, fmt.Errorf("RPC concurrency must be > 0")
    30  	}
    31  
    32  	sem := make(chan struct{}, capacity)
    33  
    34  	for i := 0; i < capacity; i++ {
    35  		sem <- struct{}{}
    36  	}
    37  
    38  	return &FixedSizeBarrier{
    39  		capacity:     capacity,
    40  		capacityInfo: fmt.Sprintf("%d", capacity),
    41  		sem:          sem,
    42  	}, nil
    43  }
    44  
    45  func (b *FixedSizeBarrier) Acquire() {
    46  	<-b.sem
    47  }
    48  
    49  func (b *FixedSizeBarrier) Release() {
    50  	b.sem <- struct{}{}
    51  }
    52  
    53  func (b *FixedSizeBarrier) BusyCount() int {
    54  	// The number of in-flight request is the
    55  	// the number of initial capacity "tickets" (concurrency)
    56  	// minus the size of the semaphore channel
    57  	return b.capacity - len(b.sem)
    58  }
    59  
    60  func (b *FixedSizeBarrier) Capacity() int {
    61  	return b.capacity
    62  }
    63  
    64  func (b *FixedSizeBarrier) CapacityInfo() string {
    65  	return b.capacityInfo
    66  }
    67  
    68  func (FixedSizeBarrier) Exhausted() {}
    69  
    70  func (FixedSizeBarrier) HasDynamicCapacity() (res bool) { return }
    71  
    72  func (FixedSizeBarrier) Start() {}
    73  
    74  func (FixedSizeBarrier) Stop() {}