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, } }