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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Data race when invoking services after shutdown #34

Closed
ivanduka opened this issue Apr 28, 2023 · 1 comment
Closed

Data race when invoking services after shutdown #34

ivanduka opened this issue Apr 28, 2023 · 1 comment

Comments

@ivanduka
Copy link

ivanduka commented Apr 28, 2023

I am not sure if this is a problem or a feature, but invoking dependencies after shutdown creates a race condition (runnable code at https://goplay.tools/snippet/vIQ3Pwu4lw1):

package main

import (
	"log"
	"sync"
	"time"

	"github.com/samber/do"
)

type Service struct{}

func main() {
	var wg sync.WaitGroup

	i := do.New()

	do.Provide(i, func(injector *do.Injector) (*Service, error) {
		return &Service{}, nil
	})

	// uncommenting the line below gives an error: `Invoking after shutdown error: DI: could not find service `*main.Service`, available services:`
	//_ = do.MustInvoke[*Service](i)

	wg.Add(1)

	go func() {
		defer wg.Done()

		time.Sleep(time.Second * 1)

		_, err := do.Invoke[*Service](i)
		if err != nil {
			log.Printf("Invoking after shutdown error: %v\n", err)
			return
		}
	}()

	err := i.Shutdown()
	if err != nil {
		log.Printf("Shutdown error: %v\n", err)
	}

	wg.Wait()

	log.Println("Finished")
}

When running with go run -race . it detects a race condition:

==================
WARNING: DATA RACE
Write at 0x00c0000b60c8 by goroutine 6:
  github.com/samber/do.(*Injector).onServiceInvoke()
      /Users/ivand/go/pkg/mod/github.com/samber/do@v1.6.0/injector.go:278 +0x120
  github.com/samber/do.InvokeNamed[...]()
      /Users/ivand/go/pkg/mod/github.com/samber/do@v1.6.0/di.go:128 +0xc8
  github.com/samber/do.Invoke[...]()
      /Users/ivand/go/pkg/mod/github.com/samber/do@v1.6.0/di.go:101 +0x6c
  main.main.func2()
      /Users/ivand/IdeaProjects/untitled1/main.go:32 +0x7c

Previous read at 0x00c0000b60c8 by main goroutine:
  github.com/samber/do.(*Injector).Shutdown()
      /Users/ivand/go/pkg/mod/github.com/samber/do@v1.6.0/injector.go:124 +0x1b0
  main.main()
      /Users/ivand/IdeaProjects/untitled1/main.go:39 +0x130

Goroutine 6 (running) created at:
  main.main()
      /Users/ivand/IdeaProjects/untitled1/main.go:27 +0x128
==================
2023/04/28 12:55:27 Finished
Found 1 data race(s)
exit status 66

Is this the intended way it supposed to work? Is the shutdown procedure expected to be a final call with no invoking of services after it?

I haven't dug deeply in the source code, but apparently the shutdown procedure does not operate under the write lock. Is there a particular reason for that?

@samber
Copy link
Owner

samber commented May 5, 2024

It has been fixed in 58b08d4

We added more thread safety in v2 (currently in RC)

@samber samber closed this as completed May 5, 2024
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

No branches or pull requests

2 participants