mirror of
https://github.com/blindlobstar/go-interview-problems
synced 2025-04-22 01:35:15 +00:00
rate tracker problem
This commit is contained in:
parent
d7f6343df1
commit
8f17fc60ba
7
13-rate-tracker/README.md
Normal file
7
13-rate-tracker/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Rate Tracker
|
||||
You are given a `Handler` with a method `Handle()` that performs some work. Your task is to implement the `LogRate` method, which reports how many times `Handle()` is called during each time interval of duration `d`.
|
||||
|
||||
The `LogRate` method should periodically report the number of `Handle()` calls that occurred in each interval by calling `monitor.SendRate(int)`.
|
||||
|
||||
## Tags
|
||||
`Concurrency`
|
29
13-rate-tracker/solution/solution.go
Normal file
29
13-rate-tracker/solution/solution.go
Normal file
@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Monitor interface {
|
||||
SendRate(int)
|
||||
}
|
||||
|
||||
type Handler struct {
|
||||
cnt atomic.Int32
|
||||
}
|
||||
|
||||
func (h *Handler) Handle() {
|
||||
// Some work
|
||||
// Calculate rate of this function
|
||||
h.cnt.Add(1)
|
||||
}
|
||||
|
||||
func (h *Handler) LogRate(monitor Monitor, d time.Duration) {
|
||||
go func() {
|
||||
for range time.After(d) {
|
||||
cnt := h.cnt.Swap(0)
|
||||
monitor.SendRate(int(cnt))
|
||||
}
|
||||
}()
|
||||
}
|
19
13-rate-tracker/task.go
Normal file
19
13-rate-tracker/task.go
Normal file
@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Monitor interface {
|
||||
SendRate(int)
|
||||
}
|
||||
|
||||
type Handler struct{}
|
||||
|
||||
func (h *Handler) Handle() {
|
||||
// Some work
|
||||
// Calculate rate of this function
|
||||
}
|
||||
|
||||
func (h *Handler) LogRate(monitor Monitor, d time.Duration) {
|
||||
}
|
99
13-rate-tracker/task_test.go
Normal file
99
13-rate-tracker/task_test.go
Normal file
@ -0,0 +1,99 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type mockMonitor struct {
|
||||
mu sync.Mutex
|
||||
rateValues []int
|
||||
}
|
||||
|
||||
func newMockMonitor() *mockMonitor {
|
||||
return &mockMonitor{
|
||||
rateValues: make([]int, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mockMonitor) SendRate(rate int) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.rateValues = append(m.rateValues, rate)
|
||||
}
|
||||
|
||||
func (m *mockMonitor) GetRateValues() []int {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
result := make([]int, len(m.rateValues))
|
||||
copy(result, m.rateValues)
|
||||
return result
|
||||
}
|
||||
|
||||
func TestHandler(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
handlerCalls int
|
||||
tickDuration time.Duration
|
||||
monitoringTime time.Duration
|
||||
expectedRates []int
|
||||
}{
|
||||
{
|
||||
name: "No calls",
|
||||
handlerCalls: 0,
|
||||
tickDuration: 100 * time.Millisecond,
|
||||
monitoringTime: 250 * time.Millisecond,
|
||||
expectedRates: []int{0, 0},
|
||||
},
|
||||
{
|
||||
name: "Single call",
|
||||
handlerCalls: 1,
|
||||
tickDuration: 100 * time.Millisecond,
|
||||
monitoringTime: 250 * time.Millisecond,
|
||||
expectedRates: []int{1, 0},
|
||||
},
|
||||
{
|
||||
name: "Multiple calls",
|
||||
handlerCalls: 1000,
|
||||
tickDuration: 100 * time.Millisecond,
|
||||
monitoringTime: 250 * time.Millisecond,
|
||||
expectedRates: []int{1000, 0},
|
||||
},
|
||||
{
|
||||
name: "Custom tick duration",
|
||||
handlerCalls: 5,
|
||||
tickDuration: 200 * time.Millisecond,
|
||||
monitoringTime: 450 * time.Millisecond,
|
||||
expectedRates: []int{5, 0},
|
||||
},
|
||||
{
|
||||
name: "Cancel stops monitoring",
|
||||
handlerCalls: 5,
|
||||
tickDuration: 100 * time.Millisecond,
|
||||
monitoringTime: 150 * time.Millisecond,
|
||||
expectedRates: []int{5},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
h := &Handler{}
|
||||
monitor := newMockMonitor()
|
||||
|
||||
for range tt.handlerCalls {
|
||||
go func() {
|
||||
h.Handle()
|
||||
}()
|
||||
}
|
||||
|
||||
time.Sleep(tt.monitoringTime)
|
||||
|
||||
rateValues := monitor.GetRateValues()
|
||||
if reflect.DeepEqual(rateValues, tt.expectedRates) {
|
||||
t.Errorf("Expected: %v, got: %v", tt.expectedRates, rateValues)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -30,6 +30,7 @@ Here is a list of the problems available in the repository. Problems are organiz
|
||||
* [Concurrent Queue](10-concurrent-queue/)
|
||||
* [Concurrent Queue II](11-concurrent-queue-ii/)
|
||||
* [Concurrent Queue III](12-concurrent-queue-iii/)
|
||||
* [Rate Tracker](13-rate-tracker/)
|
||||
|
||||
## Contributing
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user