simultaneous

package module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 8, 2025 License: MIT Imports: 2 Imported by: 1

README

simultaneous - limit the number of concurrent operations, Go

GoDoc unit tests report card codecov

Install:

go get github.com/singlestore-labs/simultaneous

Simultaneous limits the number of concurrent operations. It supports passing proof of obtaining a limit.

Simple usage

var limit = simultaneous.New[any](10)

func unlimitedWait() {
	defer limit.Forever()()
	// do stuff
}

func limitedWait() error {
	done, err := limit.Timeout(time.Minute)
	if err != nil { 
		return fmt.Errorf("timeout: %w", err)
	}
	defer done()

	// do stuff
}

Proving that operating within a limit

You can prove that you've got permission

type myLimitType struct{}

var limit = simultaneous.New[myLimitType](10)

func wantsProof(_ Enforced[myLimitType]) {
	// do something
}

func providesProof() {
	done := limit.Forever()
	defer done()
	wantsProof(done)
}

Documentation

Overview

Package simultaneous exists to place a limit on simultaneous actions that need a limit.

Index

Constants

This section is empty.

Variables

View Source
var ErrTimeout errors.String = "could not get permission to run before timeout"

Functions

This section is empty.

Types

type Enforced

type Enforced[T any] interface {
	// contains filtered or unexported methods
}

Enforced is a type that exists just to signal that a simultaneous limit is being enforced. When passing a Limited as a argument, have the receiver take an Enforced instead.

func Unlimited

func Unlimited[T any]() Enforced[T]

Unlimited provides a way to bypass enforcement

type Limit

type Limit[T any] struct {
	// contains filtered or unexported fields
}

Limit implements Enforced so it can be used to fulfill the Enforced contract.

func New

func New[T any](limit int) *Limit[T]

New takes both a type and a count. The type is so that if the limit is passed around it can be done so with type safety so that a limit of one kind of thing cannot be used as limit of another kind of thing. If you're not passing the resulting limit around, then the type argument can be anything. Like "string".

func (*Limit[T]) Forever

func (l *Limit[T]) Forever() Limited[T]

Forever waits until there is space in the Limit for another simultaneous runner. It will wait forever. The Done() method must be called to release the space.

defer limit.Forever().Done()

func (Limit[T]) SetForeverMessaging

func (l Limit[T]) SetForeverMessaging(stuckTimeout time.Duration, stuckCallback func(), unstuckCallback func()) *Limit[T]

SetForeverMessaging returns a modified Limit that changes the behavior of Forever() so that it will call stuckCallback() (if set) after waiting for stuckTimeout duration. If past that duration, and it will call unstuckCallback() (if set) when it finally gets a limit.

func (*Limit[T]) Timeout

func (l *Limit[T]) Timeout(timeout time.Duration) (Limited[T], error)

Timeout waits for a limited time for there to be space for another simultaneous runner. In the case of a timeout, ErrTimeout is returned and the Done method is a no-op. If there is room, the Done method must be invoked to make room for another runner.

type Limited

type Limited[T any] interface {
	Enforced[T]
	Done()
}

Limited is a type to take as a parameter so that the type system enforces that a reservation has been taken and limits are obeyed.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL