Important
This library is still using the main-2.0 branch of the ClockBound daemon.
A distributed locking library (port of spindle) built on aws/clock-bound, and PostgreSQL (storage).
Using this library requires the ClockBound daemon (making it AWS-only), and CGO, due to its dependency on the clockbound-ffi-go library.
One use case for this library is leader election. If you want one host/node/pod to be the leader within a cluster/group, you can achieve that with this library. When the leader fails, it will fail over to another host/node/pod within a specific timeout. That said, you might want to check out hedge-cb, which is a memberlist tracking library built on top of this library.
At the moment, the table needs to be created beforehand (spindle and locktable are just examples):
-- create the database:
CREATE DATABASE spindle;
-- create the table:
CREATE TABLE locktable (
name TEXT PRIMARY KEY,
heartbeat TIMESTAMP,
token TIMESTAMP,
writer TEXT
);After creating the lock object, you will call the Run(...) function which will attempt to acquire a named lock at a regular interval (lease duration) until cancelled. A HasLock() function is provided which returns true (along with the lock token) if the lock is successfully acquired. Something like:
import (
...
"github.com/flowerinthenight/spindle-cb"
_ "github.com/jackc/pgx/v5/stdlib"
)
func main() {
// error checks redacted
db, _ := sql.Open("pgx", *dbstr)
defer db.Close()
done := make(chan error, 1) // notify me when done (optional)
quit, cancel := context.WithCancel(context.Background()) // for cancel
// Create the lock object using a 5s lease duration using 'locktable' above.
lock := spindle.New(db, "locktable", "mylock", spindle.WithDuration(5000))
lock.Run(quit, done) // start the main loop, async
time.Sleep(time.Second * 20)
locked, token := lock.HasLock()
log.Println("HasLock:", locked, token)
time.Sleep(time.Second * 20)
cancel()
<-done
}A sample cloud-init startup script is provided for spinning up an Auto Scaling Group with the ClockBound daemon already setup and running.
# Create a launch template. ImageId here is Amazon Linux, default VPC.
# You can remove the "KeyName" line if SSH access is not needed.
# (Added newlines for readability. Might not run when copied as is.)
$ aws ec2 create-launch-template \
--launch-template-name spindle-lt \
--version-description version1 \
--launch-template-data '
{
"UserData":"'"$(cat startup-aws-asg.sh | base64 -w 0)"'",
"ImageId":"ami-0fe289b44779ce58a",
"InstanceType":"t3.medium",
"KeyName":"keyName"
}'
# Create the ASG; update {target-zone} with actual value:
$ aws autoscaling create-auto-scaling-group \
--auto-scaling-group-name spindle-asg \
--launch-template LaunchTemplateName=spindle-lt,Version='1' \
--min-size 1 \
--max-size 1 \
--tags Key=Name,Value=spindle-asg \
--availability-zones {target-zone}
# You can now SSH to the instance. Note that it might take some time before
# ClockBound is running due to the need to build it in Rust. You can wait
# for the `clockbound` process, or tail the startup script output, like so:
$ tail -f /var/log/cloud-init-output.log
# Run the sample code:
# Download the latest release sample from GitHub.
$ tar xvzf spindle-{version}-x86_64-linux.tar.gz
# Run multiple instances of `example` to see locking taking place:
$ ./example -db postgres://postgres:pass@loc.rds.amazonaws.com:5432/spindleThis library is licensed under the Apache 2.0 License.