glloq

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Apr 2, 2023 License: Apache-2.0 Imports: 6 Imported by: 0

README

License Apache 2.0 Godoc Actions Status Coverage Status

Glloq

Glloq is a simple command line utility and Go library that lets you take an advisory lock on various backends before running some action. This is especially useful when you want to avoid running database migrations (for example) concurrently.

Officially supported backends currently include:

  • PostgreSQL and derivatives (CockroachDB, …)
  • MySQL and derivatives (MariaDB, …)
  • Local files

but you can very easily implement your own.

Usage

As a CLI
# By default, glloq will use a ".glloq" lock file in the current working directory.
glloq sleep 10 &
glloq echo ok  # This displays "ok" after 10 seconds

# Supported backends include PostgreSQL (CockroachDB, ...), MySQL (Maria, ...) and local files.
export GLLOQ_DSN="postgres://user:password@postgres:5432/mydb?sslmode=disable"

# This wont run concurrently
glloq run_db_migrations.sh

# You can override default timeout of 1 minute to 10 minutes.
export GLLOQ_TIMEOUT=600

# You can specify a lock key (if supported by the backend).
GLLOQ_KEY=concurrent0 glloq run_migrations_0.sh
GLLOQ_KEY=concurrent1 glloq run_migrations_1.sh
As a library

For detailed usage and examples, refer to the godoc page.

import "github.com/gilbsgilbs/glloq"

func lockWithDSN(dsn string) error {
    return glloq.UseLocker(
        &postgreslocker.Locker{}
        &glloq.Options{
            DSN: dsn,
        },
        func() error {
            // Run DB migrations or anything.
        },
    })
}

import "github.com/gilbsgilbs/glloq/postgreslocker"

func lockWithDB(db *sql.DB) error {
    locker := postgreslocker.Locker{}
    locker.DB = db

    return locker.WithLock(
        context.Background(),
        &glloq.Options{},
        func() error {
            // ...
        },
    )
}

Documentation

Overview

glloq implements advisory locks on various backends.

Checkout https://github.com/gilbsgilbs/glloq for a quick overview.

Example

The simplest way to use glloq is by using a data source name (DSN). UseLocker will take care of opening and closing any connection or socket, will wait for the backend to be available and will hold the lock and release it when you're finished.

package main

import (
	"time"

	"github.com/gilbsgilbs/glloq"
	"github.com/gilbsgilbs/glloq/anylocker"
)

func main() {
	err := glloq.UseLocker(
		&anylocker.Locker{},
		&glloq.Options{
			// This is a connection string to your backend. For SQL-based backends,
			// dburl (https://github.com/xo/dburl) is used.
			DSN: "postgres://user:password@localhost:5432/db?sslmode=disable",
			// DSN: "mysql://user:password@localhost:3006/db",
			// DSN: "file://.lock",

			// Maximum time to wait for the backend and the lock. Defaults to 1 minute.
			Timeout: 1 * time.Hour,

			// An optional lock key, if supported by the backend.
			Key: "someUniqueKey",

			// backend-specific parameters.
			Params: map[string]string{},
		},
		func() error {
			// You can run any synchronized operation here, such as database migrations.
			// It won't run concurrently.
			return nil
		},
	)
	if err != nil {
		panic(err)
	}
}
Example (FileLocker)

The file locker allows you take a lock using a local file.

package main

import (
	"context"

	"github.com/gilbsgilbs/glloq"
	"github.com/gilbsgilbs/glloq/filelocker"
)

func main() {
	locker := filelocker.Locker{}
	err := locker.WithLock(
		context.Background(),
		&glloq.Options{
			DSN: "file:///tmp/myAppLockFile.lock",
		},
		func() error {
			// ...
			return nil
		},
	)
	if err != nil {
		panic(err)
	}
}
Example (MysqlLocker)
package main

import (
	"context"
	"database/sql"

	"github.com/gilbsgilbs/glloq"
	"github.com/gilbsgilbs/glloq/mysqllocker"
)

func main() {
	var db *sql.DB

	locker := mysqllocker.Locker{}
	locker.DB = db

	err := locker.WithLock(
		context.Background(),
		&glloq.Options{
			Params: map[string]string{
				// Name of the table that will be created to take locks.
				// Defaults to glloq.
				"table_name": "my_lock_table",
			},
		},
		func() error {
			// ...
			return nil
		},
	)
	if err != nil {
		panic(err)
	}
}
Example (PostgresLocker)
package main

import (
	"context"
	"database/sql"

	"github.com/gilbsgilbs/glloq"
	"github.com/gilbsgilbs/glloq/postgreslocker"
)

func main() {
	var db *sql.DB

	locker := postgreslocker.Locker{}
	locker.DB = db

	err := locker.WithLock(
		context.Background(),
		&glloq.Options{
			Params: map[string]string{
				// Name of the table that will be created to take locks.
				// Defaults to glloq.
				"table_name": "my_lock_table",
			},
		},
		func() error {
			// ...
			return nil
		},
	)
	if err != nil {
		panic(err)
	}
}

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrUnsupportedDSN = errors.New("glloq: DSN unknown or unsupported")
	ErrDSNNotSet      = errors.New("glloq: GLLOQ_DSN environment is not set")
	ErrTimeout        = errors.New("glloq: timeout")
)

Functions

func UseLocker

func UseLocker(locker Locker, opts *Options, fn func() error) error

UseLocker waits for a locker to hold the lock then calls fn().

Types

type Locker

type Locker interface {
	// SupportsDSN returns true if the DSN is supported by the Locker.
	SupportsDSN(dsn string) bool

	// Open allows the locker to open a connection to the backend.
	Open(ctx context.Context, dsn string) error

	// Close allows the locker to close the connection to the backend
	Close() error

	// Holds the lock. Returns ErrTimeout if context is done.
	WithLock(ctx context.Context, opts *Options, fn func() error) error
}

type Options

type Options struct {
	// DSN is the connection string to the database.
	DSN string

	// Key is a lock key.
	Key string

	// Timeout defines how long to wait for the backend to be up.
	Timeout time.Duration

	// Params are beckend-specific options.
	Params map[string]string
}

Options lock options.

type SQLLocker

type SQLLocker struct {
	DB *sql.DB
}

SQLLocker implements some base locker methods for SQL-based backends.

func (*SQLLocker) Close

func (l *SQLLocker) Close() error

func (*SQLLocker) DBUrlDriver

func (l *SQLLocker) DBUrlDriver(dsn string) string

func (*SQLLocker) Open

func (l *SQLLocker) Open(ctx context.Context, dsn string) error

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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