Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: block unlock with limit concurrency #559

Merged

Conversation

rfyiamcool
Copy link

change

see title 馃榿

@JohnRoesler
Copy link
Contributor

Do you have sample code or a test that creates the issue?

@rfyiamcool
Copy link
Author

test

when running using the latest gocron version, the following code will directly report an error. but no error will be reported when using the code in pr.

Mainly test the blocking behavior of unlock.

package main

import (
	"context"
	"fmt"
	"sync"
	"sync/atomic"
	"time"

	"github.com/go-co-op/gocron"
)

var _ gocron.Locker = (*locker)(nil)

type locker struct {
	mu    sync.Mutex
	store map[string]struct{}
}

func (l *locker) Lock(_ context.Context, key string) (gocron.Lock, error) {
	l.mu.Lock()
	defer l.mu.Unlock()
	if _, ok := l.store[key]; ok {
		return nil, gocron.ErrFailedToObtainLock
	}
	l.store[key] = struct{}{}
	return &lock{key: key, locker: l}, nil
}

var _ gocron.Lock = (*lock)(nil)

type lock struct {
	key    string
	locker *locker
}

func (l *lock) Unlock(_ context.Context) error {
	l.locker.mu.Lock()
	defer l.locker.mu.Unlock()
	delete(l.locker.store, l.key)
	return nil
}

func main() {
	var (
		queue   = make(chan int, 1)
		counter int64
		start   = time.Now()
	)

	mutex := &locker{
		store: map[string]struct{}{},
	}

	s := gocron.NewScheduler(time.UTC)
	s.WithDistributedLocker(mutex)
	s.SetMaxConcurrentJobs(1, gocron.WaitMode)

	// 1s
	s.Every(1).Seconds().Do(func() {
	})

	// 200ms
	s.Every(200).Milliseconds().Do(func() {
		atomic.AddInt64(&counter, 1)
		queue <- 1

		// fmt.Println("call 200ms")
	})

	s.StartAsync()

	var last time.Time
	for range queue {
		if last.IsZero() {
			last = time.Now()
			continue
		}

		fmt.Println(time.Since(last).String())
		if counter == 100 {
			break
		}
		if time.Since(last) > 220*time.Millisecond {
			panic("block")
		}
		last = time.Now()
	}

	fmt.Println(time.Since(start).String())
}

use lastest gocron code.

image

use code in pr.

image

Copy link
Contributor

@JohnRoesler JohnRoesler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the test 馃憤

@JohnRoesler JohnRoesler merged commit b339f73 into go-co-op:main Sep 4, 2023
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants