first commit
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
package enrollment
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// IdempotencyStore stores results keyed by idempotency key.
|
||||
var (
|
||||
store map[string]string
|
||||
storeMutex sync.RWMutex
|
||||
)
|
||||
|
||||
// InitStore initializes the in-memory store.
|
||||
func InitStore() {
|
||||
store = make(map[string]string)
|
||||
}
|
||||
|
||||
// EnrollCourseIdempotent processes an enrollment with idempotency key.
|
||||
// If key exists, returns existing result immediately. If not, simulates
|
||||
// 1.5s work, stores and returns result.
|
||||
func EnrollCourseIdempotent(key string) string {
|
||||
// check read lock first
|
||||
storeMutex.RLock()
|
||||
if res, ok := store[key]; ok {
|
||||
storeMutex.RUnlock()
|
||||
return res
|
||||
}
|
||||
storeMutex.RUnlock()
|
||||
|
||||
// Acquire write lock to ensure only one goroutine does the processing
|
||||
storeMutex.Lock()
|
||||
// double-check after acquiring write lock
|
||||
if res, ok := store[key]; ok {
|
||||
storeMutex.Unlock()
|
||||
return res
|
||||
}
|
||||
|
||||
// Simulate processing (1.5s)
|
||||
time.Sleep(1500 * time.Millisecond)
|
||||
res := fmt.Sprintf("enrolled-successful-for-key-%s", key)
|
||||
|
||||
// Save and release lock
|
||||
store[key] = res
|
||||
storeMutex.Unlock()
|
||||
return res
|
||||
}
|
||||
|
||||
// RunConcurrentEnrollments runs n goroutines that call EnrollCourseIdempotent with same key.
|
||||
// Returns map: which goroutine got what result and runtime info.
|
||||
func RunConcurrentEnrollments(key string, n int) map[string]interface{} {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(n)
|
||||
resCh := make(chan string, n)
|
||||
start := time.Now()
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
go func(id int) {
|
||||
defer wg.Done()
|
||||
r := EnrollCourseIdempotent(key)
|
||||
resCh <- fmt.Sprintf("goroutine-%d: %s", id+1, r)
|
||||
}(i)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(resCh)
|
||||
out := make([]string, 0, n)
|
||||
for r := range resCh {
|
||||
out = append(out, r)
|
||||
}
|
||||
duration := time.Since(start)
|
||||
return map[string]interface{}{
|
||||
"key": key,
|
||||
"count": n,
|
||||
"duration": duration.String(),
|
||||
"results": out,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user