From 0d33364a9008f158611f84d708f3d1a41a855174 Mon Sep 17 00:00:00 2001 From: blindlobstar Date: Thu, 3 Apr 2025 20:25:19 +0200 Subject: [PATCH] first successful key lookup problem --- 01-first-successful-key-lookup/README.md | 14 +++++ .../solution/solution.go | 52 +++++++++++++++++++ 01-first-successful-key-lookup/task.go | 19 +++++++ README.md | 5 ++ 4 files changed, 90 insertions(+) create mode 100644 01-first-successful-key-lookup/README.md create mode 100644 01-first-successful-key-lookup/solution/solution.go create mode 100644 01-first-successful-key-lookup/task.go diff --git a/01-first-successful-key-lookup/README.md b/01-first-successful-key-lookup/README.md new file mode 100644 index 0000000..cba66bf --- /dev/null +++ b/01-first-successful-key-lookup/README.md @@ -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** diff --git a/01-first-successful-key-lookup/solution/solution.go b/01-first-successful-key-lookup/solution/solution.go new file mode 100644 index 0000000..cfc8327 --- /dev/null +++ b/01-first-successful-key-lookup/solution/solution.go @@ -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 + } + } +} diff --git a/01-first-successful-key-lookup/task.go b/01-first-successful-key-lookup/task.go new file mode 100644 index 0000000..a574199 --- /dev/null +++ b/01-first-successful-key-lookup/task.go @@ -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 +} diff --git a/README.md b/README.md index 420ec9b..e354565 100644 --- a/README.md +++ b/README.md @@ -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