80 lines
1.8 KiB
Go
80 lines
1.8 KiB
Go
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,
|
|
}
|
|
}
|