Git Product home page Git Product logo

Comments (3)

techschool avatar techschool commented on August 10, 2024

Hey Huangbo,
The race issue is indeed caused by the validator engine being called multiple times by the parallel test cases (when they create a new server).
So the solution is to just move it out of the NewServer() function, and put it inside the special init() function:

func init() {
	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
		v.RegisterValidation("currency", validCurrency)
	}
}

// NewServer creates a new HTTP server and set up routing.
func NewServer(config util.Config, store db.Store) (*Server, error) {
	tokenMaker, err := token.NewPasetoMaker(config.TokenSymmetricKey)
	if err != nil {
		return nil, fmt.Errorf("cannot create token maker: %w", err)
	}

	server := &Server{
		config:     config,
		store:      store,
		tokenMaker: tokenMaker,
	}

	server.setupRouter()
	return server, nil
}

If you have any further questions, don't hesitate to join Tech School's discord group to discuss directly with me and other student: https://bit.ly/techschooldc

from simplebank.

boh5 avatar boh5 commented on August 10, 2024

@techschool Thanks for your reply, your solution do save me!

I understand now that register validator in init() function make sure RegisterValidation called only once.

But I'm still confused why the sync.Mutex not working.
According to the RegisterValidation doc, it say "if the key already exists, the previous validation function will be replaced.", I think it should works well, even if it's inefficient. Am I use the mutex in a wrong way?

Here the way I use mutex:

var mutex sync.Mutex

// NewServer creates a new HTTP server and setup routing
func NewServer(config util.Config, store db.Store) (*Server, error) {
	tokenMaker, err := token.NewPasetoMaker(config.TokenSymmetricKey)
	if err != nil {
		return nil, fmt.Errorf("cannot create token make: %w", err)
	}
	server := &Server{
		config:     config,
		store:      store,
		tokenMaker: tokenMaker,
	}
	
	mutex.Lock()
	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
		err := v.RegisterValidation("currency", validCurrency)
		if err != nil {
			log.Fatal("register validation err:", err)
		}
	}
	mutex.Unlock()
	
	server.setupRouter()

	return server, nil
}

Sorry to bother again.

from simplebank.

frogfromlake avatar frogfromlake commented on August 10, 2024

@techschool Thanks for your reply, your solution do save me!

I understand now that register validator in init() function make sure RegisterValidation called only once.

But I'm still confused why the sync.Mutex not working. According to the RegisterValidation doc, it say "if the key already exists, the previous validation function will be replaced.", I think it should works well, even if it's inefficient. Am I use the mutex in a wrong way?

Here the way I use mutex:

var mutex sync.Mutex

// NewServer creates a new HTTP server and setup routing
func NewServer(config util.Config, store db.Store) (*Server, error) {
	tokenMaker, err := token.NewPasetoMaker(config.TokenSymmetricKey)
	if err != nil {
		return nil, fmt.Errorf("cannot create token make: %w", err)
	}
	server := &Server{
		config:     config,
		store:      store,
		tokenMaker: tokenMaker,
	}
	
	mutex.Lock()
	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
		err := v.RegisterValidation("currency", validCurrency)
		if err != nil {
			log.Fatal("register validation err:", err)
		}
	}
	mutex.Unlock()
	
	server.setupRouter()

	return server, nil
}

Sorry to bother again.

The mutexes are not working because each test runs in its own goroutine when you use t.Parallel().
Each test gets its own instance of the mutex, so the mutex doesn't prevent the concurrent execution of the tests which leads to race conditions where multiple tests try to acquire the lock at the same time.
so even if you declare a mutex outside the function, each test will have its own instance of the mutex. Quang's solution is the way to go i guess.

from simplebank.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.