Skip to content

Instantly share code, notes, and snippets.

@revilon1991
Created October 13, 2024 07:09
Show Gist options
  • Save revilon1991/e57b27a5a5655c27d081a4a3ced7cdc6 to your computer and use it in GitHub Desktop.
Save revilon1991/e57b27a5a5655c27d081a4a3ced7cdc6 to your computer and use it in GitHub Desktop.
Golang API, WaitGroup, Semaphore, Cancel Context, Recovery Panic, Safe Map Mutex Result goroutine
package main
import (
"context"
"encoding/json"
"fmt"
"net/http"
"runtime/debug"
"strconv"
"sync"
)
const (
semaphoreFrequency = 10
)
func handler(w http.ResponseWriter, r *http.Request) {
var wg sync.WaitGroup
sem := &semaphore{c: make(chan struct{}, semaphoreFrequency)}
tInfos := &testInfos{m: make(map[string]string)}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
goroutines := []string{"1", "2", "3", "4", "5", "6", "7", "8", "9"}
for i, _ := range goroutines {
wg.Add(1)
go func(i int) {
defer sem.release()
defer wg.Done()
defer func() {
if r := recover(); r != nil {
fmt.Printf("recovered from panic: %v\n%s\n", r, debug.Stack())
cancel()
tInfos.set(strconv.Itoa(i), "err "+strconv.Itoa(i))
}
}()
sem.acquire()
select {
case <-ctx.Done():
tInfos.set(strconv.Itoa(i), "skip "+strconv.Itoa(i))
default:
do(i, tInfos)
}
}(i)
}
wg.Wait()
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
_ = json.NewEncoder(w).Encode(struct {
Code int `json:"code"`
Result []string `json:"result"`
}{
Code: http.StatusOK,
Result: tInfos.values(),
})
}
func main() {
http.HandleFunc("/", handler)
fmt.Println("Server is running http://localhost:8080")
http.ListenAndServe(":8080", nil)
}
func do(i int, t *testInfos) {
//time.Sleep(1 * time.Second)
if i == 2 {
panic("panic " + strconv.Itoa(i))
}
t.set(strconv.Itoa(i), "Done "+strconv.Itoa(i))
}
type testInfos struct {
mu sync.Mutex
m map[string]string
}
func (idi *testInfos) set(index string, value string) {
idi.mu.Lock()
defer idi.mu.Unlock()
idi.m[index] = value
}
func (idi *testInfos) get(index string) (string, bool) {
idi.mu.Lock()
defer idi.mu.Unlock()
value, ok := idi.m[index]
return value, ok
}
func (idi *testInfos) len() int {
idi.mu.Lock()
defer idi.mu.Unlock()
return len(idi.m)
}
func (idi *testInfos) values() []string {
idi.mu.Lock()
defer idi.mu.Unlock()
values := make([]string, 0, len(idi.m))
for _, value := range idi.m {
values = append(values, value)
}
return values
}
type semaphore struct {
c chan struct{}
}
func (s *semaphore) acquire() {
s.c <- struct{}{}
}
func (s *semaphore) release() {
<-s.c
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment