Skip to content

Commit

Permalink
Prevent adding to an eventloop when reserve was for a previous start
Browse files Browse the repository at this point in the history
This basically fixes promises or reservations from previous iterations
to be executed in next ones, most likely across scenarios.

This probably need a better solution and some better notification apart
from the context getting canceled but that seems at least currently to
be way more involved
  • Loading branch information
mstoykov committed Nov 15, 2021
1 parent f34e3de commit c78d921
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 5 deletions.
10 changes: 10 additions & 0 deletions js/eventloop.go
Expand Up @@ -30,6 +30,7 @@ import (
type eventLoop struct {
queueLock sync.Mutex
queue []func()
started int
wakeupCh chan struct{} // maybe use sync.Cond ?
reservedCount int
}
Expand Down Expand Up @@ -60,10 +61,15 @@ func (e *eventLoop) RunOnLoop(f func()) {
func (e *eventLoop) Reserve() func(func()) {
e.queueLock.Lock()
e.reservedCount++
started := e.started
e.queueLock.Unlock()

return func(f func()) {
e.queueLock.Lock()
if started != e.started {
e.queueLock.Unlock()
return
}
e.queue = append(e.queue, f)
e.reservedCount--
e.queueLock.Unlock()
Expand All @@ -78,6 +84,10 @@ func (e *eventLoop) Reserve() func(func()) {
// or the context is done
//nolint:cyclop
func (e *eventLoop) Start(ctx context.Context) {
e.queueLock.Lock()
e.started++
e.reservedCount = 0
e.queueLock.Unlock()
done := ctx.Done()
for {
select { // check if done
Expand Down
50 changes: 45 additions & 5 deletions js/eventloop_test.go
Expand Up @@ -36,15 +36,15 @@ func TestBasicEventLoop(t *testing.T) {
defer cancel()
loop.RunOnLoop(func() { ran++ })
loop.Start(ctx)
require.Equal(t, ran, 1)
require.Equal(t, 1, ran)
loop.RunOnLoop(func() { ran++ })
loop.RunOnLoop(func() { ran++ })
loop.Start(ctx)
require.Equal(t, ran, 3)
require.Equal(t, 3, ran)
loop.RunOnLoop(func() { ran++; cancel() })
loop.RunOnLoop(func() { ran++ })
loop.Start(ctx)
require.Equal(t, ran, 4)
require.Equal(t, 4, ran)
}

func TestEventLoopReserve(t *testing.T) {
Expand All @@ -66,6 +66,46 @@ func TestEventLoopReserve(t *testing.T) {
start := time.Now()
loop.Start(ctx)
took := time.Since(start)
require.Equal(t, ran, 2)
require.Greater(t, took, time.Second)
require.Equal(t, 2, ran)
require.Less(t, time.Second, took)
require.Greater(t, time.Second+time.Millisecond*100, took)
}

func TestEventLoopReserveStopBetweenStarts(t *testing.T) {
t.Parallel()
loop := newEventLoop()
var ran int
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
loop.RunOnLoop(func() {
ran++
r := loop.Reserve()
go func() {
time.Sleep(time.Second)
r(func() {
ran++
})
}()
})
go func() {
time.Sleep(200 * time.Millisecond)
cancel()
}()
loop.Start(ctx)
require.Equal(t, 1, ran)

ctx, cancel = context.WithCancel(context.Background())
defer cancel()
loop.RunOnLoop(func() {
ran++
r := loop.Reserve()
go func() {
time.Sleep(time.Second)
r(func() {
ran++
})
}()
})
loop.Start(ctx)
require.Equal(t, 3, ran)
}

0 comments on commit c78d921

Please sign in to comment.