Skip to content

Commit

Permalink
Merge pull request #68 from whywaita/fix/67
Browse files Browse the repository at this point in the history
Implement datastore lock
  • Loading branch information
whywaita authored Jun 10, 2021
2 parents 554f964 + 3b09061 commit 353c09f
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 0 deletions.
23 changes: 23 additions & 0 deletions cmd/server/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import (
"context"
"fmt"
"log"
"strings"
"time"

"github.com/whywaita/myshoes/pkg/logger"

"github.com/whywaita/myshoes/internal/config"
"github.com/whywaita/myshoes/pkg/datastore"
Expand Down Expand Up @@ -61,6 +65,25 @@ func (m *myShoes) Run() error {
eg := errgroup.Group{}
ctx := context.Background()

for {
logger.Logf(false, "start getting lock...")
isLocked, err := m.ds.IsLocked(ctx)
if err != nil {
return fmt.Errorf("failed to check lock: %w", err)
}

if strings.EqualFold(isLocked, datastore.IsNotLocked) {
if err := m.ds.GetLock(ctx); err != nil {
return fmt.Errorf("failed to get lock: %w", err)
}

logger.Logf(false, "get lock successfully!")
break
}

time.Sleep(time.Second)
}

eg.Go(func() error {
if err := web.Serve(ctx, m.ds); err != nil {
return fmt.Errorf("failed to serve: %w", err)
Expand Down
10 changes: 10 additions & 0 deletions pkg/datastore/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ var (
ErrNotFound = errors.New("not found")
)

// Lock values
var (
IsLocked = "is locked"
IsNotLocked = "is not locked"
)

// Datastore is persistent storage
type Datastore interface {
CreateTarget(ctx context.Context, target Target) error
Expand All @@ -39,6 +45,10 @@ type Datastore interface {
ListRunners(ctx context.Context) ([]Runner, error)
GetRunner(ctx context.Context, id uuid.UUID) (*Runner, error)
DeleteRunner(ctx context.Context, id uuid.UUID, deletedAt time.Time, reason RunnerStatus) error

// Lock
GetLock(ctx context.Context) error
IsLocked(ctx context.Context) (string, error)
}

// Target is a target repository that will add auto-scaling runner.
Expand Down
10 changes: 10 additions & 0 deletions pkg/datastore/memory/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,13 @@ func (m *Memory) DeleteRunner(ctx context.Context, id uuid.UUID, deletedAt time.
delete(m.runners, id)
return nil
}

// GetLock get lock
func (m *Memory) GetLock(ctx context.Context) error {
return nil
}

// IsLocked return status of lock
func (m *Memory) IsLocked(ctx context.Context) (string, error) {
return datastore.IsNotLocked, nil
}
44 changes: 44 additions & 0 deletions pkg/datastore/mysql/lock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package mysql

import (
"context"
"fmt"

"github.com/whywaita/myshoes/pkg/datastore"
)

const (
// LockKey is key of database lock
LockKey = "myshoes"
)

// GetLock get lock
func (m *MySQL) GetLock(ctx context.Context) error {
var res int

query := fmt.Sprintf(`SELECT GET_LOCK('%s', 10)`, LockKey)
if err := m.Conn.GetContext(ctx, &res, query); err != nil {
return fmt.Errorf("failed to GET_LOCK: %w", err)
}

return nil
}

// IsLocked return status of lock
func (m *MySQL) IsLocked(ctx context.Context) (string, error) {
var res int

query := fmt.Sprintf(`SELECT IS_FREE_LOCK('%s')`, LockKey)
if err := m.Conn.GetContext(ctx, &res, query); err != nil {
return "", fmt.Errorf("failed to IS_FREE_LOCK: %w", err)
}

switch res {
case 1:
return datastore.IsNotLocked, nil
case 0:
return datastore.IsLocked, nil
}

return "", fmt.Errorf("IS_FREE_LOCK return NULL")
}

0 comments on commit 353c09f

Please sign in to comment.