mirror of
https://github.com/blindlobstar/go-interview-problems
synced 2025-04-22 17:55:16 +00:00
first successful key lookup problem
This commit is contained in:
parent
50fd93c5a0
commit
0d33364a90
14
01-first-successful-key-lookup/README.md
Normal file
14
01-first-successful-key-lookup/README.md
Normal file
@ -0,0 +1,14 @@
|
||||
# First Successful Key Lookup
|
||||
|
||||
You are given a function `get(ctx, address, key)`, which retrieves a value for a given key from a remote address. However, you don't know which address has the value, and network calls can fail.
|
||||
|
||||
Your task is to implement the Get function that:
|
||||
* Calls get for each address in parallel.
|
||||
* Returns the first successful response.
|
||||
* If all requests fail, returns an error.
|
||||
|
||||
## Tags
|
||||
`Concurrency`
|
||||
|
||||
## Source
|
||||
- [Mock-собеседование по Go от Team Lead из Яндекса](https://www.youtube.com/watch?v=x689QxR3AIc) by **it-interview**
|
52
01-first-successful-key-lookup/solution/solution.go
Normal file
52
01-first-successful-key-lookup/solution/solution.go
Normal file
@ -0,0 +1,52 @@
|
||||
package solution
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
var ErrNotFound = errors.New("key not found")
|
||||
|
||||
func get(ctx context.Context, address string, key string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func Get(ctx context.Context, addresses []string, key string) (string, error) {
|
||||
// Creating context with timeout, so we can cancel it when receive first response (or timeout)
|
||||
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// Channels MUST be buffered, in other case there is a goroutine leakage
|
||||
resCh, errCh := make(chan string, len(addresses)), make(chan error, len(addresses))
|
||||
|
||||
for _, address := range addresses {
|
||||
go func() {
|
||||
if val, err := get(ctx, address, key); err != nil {
|
||||
errCh <- err
|
||||
} else {
|
||||
// There is a potential goroutine leak, if channel was unbuffered.
|
||||
// If the result is not first, we WILL NOT read this channel
|
||||
// and this goroutine will stuck forever
|
||||
resCh <- val
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
var errCount int
|
||||
for {
|
||||
select {
|
||||
case err := <-errCh:
|
||||
// If error count is equal to addresses count
|
||||
// it means that no goroutine left and we can return an error
|
||||
errCount++
|
||||
if errCount == len(addresses) {
|
||||
return "", err
|
||||
}
|
||||
case val := <-resCh:
|
||||
return val, nil
|
||||
case <-ctx.Done():
|
||||
return "", context.Canceled
|
||||
}
|
||||
}
|
||||
}
|
19
01-first-successful-key-lookup/task.go
Normal file
19
01-first-successful-key-lookup/task.go
Normal file
@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
)
|
||||
|
||||
var ErrNotFound = errors.New("key not found")
|
||||
|
||||
func get(ctx context.Context, address string, key string) (string, error) {
|
||||
// Already implemented
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Call `get` function for each received address in parallel
|
||||
// Return first response or an error if all requests fail
|
||||
func Get(ctx context.Context, adresses []string, key string) (string, error) {
|
||||
return "", nil
|
||||
}
|
@ -7,6 +7,11 @@ for technical interviews. These problems focus on real-world scenarios, includin
|
||||
|
||||
Here is a list of the problems available in the repository. Problems are organized by their respective tags:
|
||||
|
||||
### Concurrency
|
||||
|
||||
* [First Successful Key Lookup](01-first-successful-key-lookup/)
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
We welcome contributions from anyone looking to add more problems, improve solutions, or provide better documentation. Please refer to
|
||||
|
Loading…
x
Reference in New Issue
Block a user