Singleflight-декоратор
Условие задачи
Реализовать обёртку Decorator над Client, чтобы при параллельных вызовах GetUser(name):
- если аргумент name одинаковый (например, "Vasya"), реальный Client.GetUser("Vasya") вызывается только один раз,
- если аргументы разные ("Vasya", "Oleg"), вызовы идут независимо.
Метод Client.GetUser — дорогостоящая операция, каждый вызов стоит денег. Необходимо добиться, чтобы GetUser(name) с одинаковым name выполнялся ровно один раз, независимо от количества параллельных вызовов. Результат должен быть расшарен между всеми вызывающими.
gotype User struct {
Id int64
}
type IClient interface {
GetUser(name string) (*User, error)
}
type Client struct {}
func (c Client) GetUser(name string) (*User, error) {
// дорогостоящая операция
return &User{}, nil
}
func NewClient() *Client {
return &Client{}
}
type Decorator struct {
client IClient
// ...
}
func (d *Decorator) GetUser(name string) (*User, error) {
// ...
}
func NewDecorator(c IClient) *Decorator {
return &Decorator{client: c}
}
Пример вызова
gofunc main() {
client := NewClient()
changedClient := NewDecorator(client)
go func() {
vasya, err := changedClient.GetUser("Vasya")
// ...
}()
go func() {
vasya, err := changedClient.GetUser("Vasya")
// ...
}()
go func() {
vasya, err := changedClient.GetUser("Vasya")
// ...
}()
go func() {
vasya, err := changedClient.GetUser("Vasya")
// ...
}()
go func() {
oleg, err := changedClient.GetUser("Oleg")
// ...
}()
go func() {
oleg, err := changedClient.GetUser("Oleg")
// ...
}()
}