โณ Fair, FIFO-style locking for Go. Everyone waits their turn โ no queue jumping allowed! ๐ฏ
go get github.com/decoi-io/waitinlineThen import it:
import "github.com/decoi-io/waitinline"waitinline is a fair locking mechanism for goroutines โ ensuring that whoever comes first, gets served first. Just like lining up at your favorite coffee shop โ๏ธ.
โ FIFO fairness โ Context-aware timeout + cancellation ๐ Clean shutdowns ๐งต Safe for concurrent use ๐ชถ Lightweight and dependency-free
line := waitinline.New(10) // queue size 10
defer line.Close()
ctx := context.Background()
pass, err := line.Lock(ctx)
if err != nil {
log.Fatal("Failed to lock:", err)
}
// ๐ง Critical section begins
pass.Unlock()package main
import (
"context"
"fmt"
"sync"
"time"
"github.com/decoi-io/waitinline"
)
func main() {
lock := waitinline.New(10)
defer lock.Close()
wg := sync.WaitGroup{}
order := []int{}
for i := range 10 {
wg.Add(1)
go func(index int) {
defer wg.Done()
ticket, err := lock.Lock(context.Background())
if err != nil {
fmt.Printf("lock failed: %v", err)
return
}
defer ticket.Unlock()
fmt.Printf("Appending index: %d\n", index)
order = append(order, index)
}(i)
time.Sleep(time.Millisecond * 100)
}
fmt.Printf("Order: %v\n", order)
}๐ Output (expected FIFO):
Appending index: 0
Appending index: 1
Appending index: 2
Appending index: 3
Appending index: 4
Appending index: 5
Appending index: 6
Appending index: 7
Appending index: 8
Appending index: 9
Order: [0 1 2 3 4 5 6 7 8 9]
Create a new fair queue (Line) with given size (max number of waiting goroutines).
Waits in line to acquire the lock.
Returns a LockHandler which should be unlocked when done.
- Respects
ctxcancellation or timeout โฑ๏ธ - If the
Lineis closed, returnsErrQueueClosed
Closes the lock system. All waiting goroutines are cancelled gracefully.
type LockHandler interface {
Unlock() error
}Returned by .Lock(). Call .Unlock() to allow the next person in line to proceed.
ErrQueueClosedโ Line was closed before lock could be acquiredErrContextCancelledโ Context timed out or was cancelledErrFailedUnlockโ Unlock failed (shouldn't happen under normal usage)
- Always
defer pass.Unlock()once you get the lock. - Call
.Close()when your app/server shuts down to clean up waiters. - Queue size defines how many can wait โ beyond that,
.Lock()will block until room.
- Job queues ๐งบ
- Rate-limiting gateways ๐ฅ
- Multiplayer turn management ๐ฎ
- Fair scheduling in microservices ๐
- Enforcing request order ๐
Great question! While sync.Mutex is fast and simple, it's not fair โ it doesnโt guarantee the order in which goroutines acquire the lock. Whoever gets scheduled next, wins. ๐โโ๏ธ๐จ
But with waitinline, you get:
- First goroutine to request the lock is guaranteed to get it first.
- This is crucial for predictable behavior in systems where ordering matters (like job queues, rate-limiting, or gameplay turns).
- You can
Lock(ctx)with cancellation or timeouts. - No more blocked goroutines forever โ you stay responsive to timeouts, cancellations, or shutdowns.
- You can
.Close()the line and gracefully cancel all waiters. No stuck goroutines or deadlocks.
- You can wrap this as a shared lock mechanism between components, without requiring them to share memory directly.
- Makes your architecture more modular ๐ง.
| Situation | Use sync.Mutex |
Use waitinline |
|---|---|---|
| ๐ง Fairness between goroutines matters | โ | โ |
| โฑ You need timeouts / cancellation support | โ | โ |
| ๐ฆ Need to cancel all waiters cleanly | โ | โ |
| ๐งฉ Components may not be tightly coupled | โ | โ |
| ๐ High-speed critical sections | โ | โ |
go test ./...We welcome issues, ideas, and pull requests! Here's how to join the fun:
- โญ Star the repo to show love!
- ๐ Found a bug? Open an issue
- ๐ฑ Want to improve something? Fork, commit, and submit a pull request!
- ๐งช Run
go test ./...before sending PRs
- Keep the package light โ no third-party dependencies.
- Maintain full test coverage for all changes.
- Use
go fmt,go vet, andgolangci-lintif you like staying sharp ๐
MIT ยฉ decoi-io
If Go had a theme park, waitinline would be the velvet rope queue keeping everyone in order ๐ข
Made with โค๏ธ and a dash of concurrency.