concurrency-limiter allows you to limit the number of goroutines accessing a resource with support for timeouts

concurrency-limiter

Mentioned in Awesome Go GoDoc reference example GoReportCard example codecov

About

concurrency-limiter allows you to limit the number of goroutines accessing a resource with support for timeouts , dynamic priority of goroutines and context cancellation of goroutines.

Installation

To install concurrency-limiter:

go get github.com/vivek-ng/concurrency-limiter

Then import concurrency-limiter to use it

    import(
        github.com/vivek-ng/concurrency-limiter/limiter
    )

    nl := limiter.New(3)
    ctx := context.Background()
    nl.Wait(ctx)
    // Perform actions .........
    nl.Finish()

Usage

Below are some examples of using this library. To run real examples , please check the examples folder.

Limiter

    import(
        github.com/vivek-ng/concurrency-limiter/limiter
    )

    func main() {
        nl := limiter.New(3)

        var wg sync.WaitGroup
        wg.Add(15)

        for i := 0; i < 15; i++ {
            go func(index int) {
                defer wg.Done()
                ctx := context.Background()
                nl.Wait(ctx)
                // in real life , this can be DB operations , message publish to queue ........
                fmt.Println("executing action...: ", "index: ", index, "current number of goroutines: ", nl.Count())
                nl.Finish()
            }(i)
        }
        wg.Wait()
    }

Priority Limiter

    import(
        github.com/vivek-ng/concurrency-limiter/priority
    )
    
    func main() {
        pr := priority.NewLimiter(1)
        var wg sync.WaitGroup
        wg.Add(15)
        for i := 0; i < 15; i++ {
            go func(index int) {
                defer wg.Done()
                ctx := context.Background()
                if index%2 == 1 {
                    pr.Wait(ctx, priority.High)
                } else {
                    pr.Wait(ctx, priority.Low)
                }
                // in real life , this can be DB operations , message publish to queue ........
                fmt.Println("executing action...: ", "index: ", index, "current number of goroutines: ", pr.Count())
                pr.Finish()
            }(i)
        }
        wg.Wait()
    }

Examples

Limiter

    nl := limiter.New(3)
    ctx := context.Background()
    nl.Wait(ctx)
    // Perform actions .........
    nl.Finish()

In the above example , there can be a maximum of 3 goroutines accessing a resource concurrently. The other goroutines are added to the waiting list and are removed and given a chance to access the resource in the FIFO order. If the context is cancelled , the goroutine is removed from the waitlist.

Limiter with Timeout

    nl := limiter.New(3,
    WithTimeout(10),
    )
    ctx := context.Background()
    nl.Wait(ctx)
    // Perform actions .........
    nl.Finish()

In the above example , the goroutines will wait for a maximum of 10 milliseconds. Goroutines will be removed from the waitlist after 10 ms even if the number of concurrent goroutines is greater than the limit specified.

Priority Limiter

    nl := priority.NewLimiter(3)
    ctx := context.Background()
    nl.Wait(ctx , priority.High)
    // Perform actions .........
    nl.Finish()

In Priority Limiter , goroutines with higher priority will be given preference to be removed from the waitlist. For instance in the above example , the goroutine will be given the maximum preference because it is of high priority. In the case of tie between the priorities , the goroutines will be removed from the waitlist in the FIFO order.

Priority Limiter with Dynamic priority

    nl := priority.NewLimiter(3,
    WithDynamicPriority(5),
    )
    ctx := context.Background()
    nl.Wait(ctx , priority.Low)
    // Perform actions .........
    nl.Finish()

In Dynamic Priority Limiter , the goroutines with lower priority will get their priority increased periodically by the time period specified. For instance in the above example , the goroutine will get it's priority increased every 5 ms. This will ensure that goroutines with lower priority do not suffer from starvation. It's highly recommended to use Dynamic Priority Limiter to avoid starving low priority goroutines.

Priority Limiter with Timeout

    nl := priority.NewLimiter(3,
    WithTimeout(30),
    WithDynamicPriority(5),
    )
    ctx := context.Background()
    nl.Wait(ctx , priority.Low)
    // Perform actions .........
    nl.Finish()

This is similar to the timeouts in the normal limiter. In the above example , goroutines will wait a maximum of 30 milliseconds. The low priority goroutines will get their priority increased every 5 ms.

Runnable Function

    nl := priority.NewLimiter(3)
    ctx := context.Background()
    nl.Run(ctx , priority.Low , func()error {
        return sendMetrics()
    })

Runnable function will allow you to wrap your function and execute them with concurrency limit. This function is a wrapper on top of the Wait() and Finish() functions.

Contribution

Please feel free to open up issues , create PRs for bugs/features. All contributions are welcome :)

Similar Resources

Go rate limiter used to ensure a minimum duration between executions.

Ratelimiter Rate limiter used to ensure a minimum duration between executions. Additionally supports the optional limit of max queue size. This can be

Jul 14, 2022

Simple-request-limiter - Example of limiting API requests using standard Go library

Route: http://localhost:8080/urls example of body in POST request that was used:

Feb 2, 2022

Redis-rate-limiter - An abstraction over redist rate/v9 package

RATE_LIMIT_POC Notes This POC is based on github.com/go-redis/redis_rate/v9 pack

Feb 14, 2022

GopherTalk: a multi-user chat powered by GO to explore its standard library and features like sockets, goroutines, channels and sync package

GopherTalk: a multi-user chat powered by GO to explore its standard library and features like sockets, goroutines, channels and sync package

GopherTalk GopherTalk is a multi-user chat powered by GO to explore its standard

Jun 6, 2022

A fast subdomain enumerator for web URLs using the power of Goroutines.

A fast subdomain enumerator for web URLs using the power of Goroutines.

gosublister A fast subdomain enumerator for web URLs written in go with goroutines. Options Usage: gosublister -u [URL] [Other Flags] Flags: -u,

May 7, 2023

Go client library for accessing the Football Data API

football-data-sdk football-data-sdk is a Go client library for accessing the Football Data API. Successful queries return native Go structs. Services

Oct 13, 2022

Client library with golang for accessing Harbor API.

go-client Client library with golang for accessing Harbor API. Client Types There are 3 swagger files in this repo. api/ v2.0/ legacy_swag

Nov 13, 2022

brickset is a Go client library for accessing the brickset.com API v3.

brickset is a Go client library for accessing the brickset.com API v3.

May 21, 2022

Multiplexer over TCP. Useful if target server only allows you to create limited tcp connections concurrently.

tcp-multiplexer Use it in front of target server and let your client programs connect it, if target server only allows you to create limited tcp conne

May 27, 2021
Comments
  • Solve starvation for low priority goroutines

    Solve starvation for low priority goroutines

    low priority goroutines sometimes will always be in the waiting state because of other high priority goroutines . We need to avoid starvation this starvation issue.

Timeouts for popular Go packages

Go Timeouts An unresponsive service can be worse than a down one. It can tie up your entire system if not handled properly. All network requests shoul

Aug 23, 2022
go HTTP client that makes it plain simple to configure TLS, basic auth, retries on specific errors, keep-alive connections, logging, timeouts etc.

goat Goat, is an HTTP client built on top of a standard Go http package, that is extremely easy to configure; no googling required. The idea is simila

Jun 25, 2022
Designed to support DNS brute-forcing with a minimal number of network connections

Fast Use of DNS Resolvers Designed to support DNS brute-forcing with a minimal number of network connections. Installation go get -v -u github.com/caf

Dec 8, 2022
Pacemaker - Rate limit library. Currently implemented rate limits are

PaceMaker Rate limit library. Currently implemented rate limits are Fixed window

Nov 5, 2022
Dhrate - Quickly check Dockerhub rate (limit) as an unauthenticated user
Dhrate - Quickly check Dockerhub rate (limit) as an unauthenticated user

Dockerhub Rate A small Go program that returns the Dockerhub rate of an unauthen

Feb 7, 2022
Ratelimit - This package provides a Golang implementation of the leaky-bucket rate limit algorithm

Go rate limiter This package provides a Golang implementation of the leaky-bucke

Jul 26, 2022
A very simple rate limiter in go, made as a learning project to learn go and rate limiting patterns!
A very simple rate limiter in go, made as a learning project to learn go and rate limiting patterns!

rate-limiter-go A very simple rate limiter in go, made as a learning project to learn go and rate limiting patterns! Demo: Running the project: To exe

Jun 1, 2022
A rate limiter for the gin framework

GinRateLimit GinRateLimit is a rate limiter for the gin framework. By default, it can only store rate limit info in memory. If you want to store it so

Dec 22, 2021
Common rate-limiter implementations

Overview An example Rate Limiter library used to control the rate that events occur, but these can also be used as thresholds that should replenish ov

Dec 1, 2021
A rate limiter for Golang, with ETCD data bindings

Go Rate limiter This package allows us to have a distributed rate limiter, using Redis as a central counter. The limits that are set are only "soft" l

Dec 9, 2021