Files
frontier/test/batch/edges/edges.go

154 lines
3.5 KiB
Go

package main
import (
"context"
"fmt"
"math/rand"
"net"
"net/http"
_ "net/http/pprof"
"os"
"strings"
"sync"
"sync/atomic"
"time"
armlog "github.com/jumboframes/armorigo/log"
"github.com/jumboframes/armorigo/sigaction"
"github.com/singchia/frontier/api/dataplane/v1/edge"
"github.com/singchia/go-timer/v2"
"github.com/spf13/pflag"
)
var (
edges = map[int]edge.Edge{}
mtx sync.RWMutex
)
func main() {
network := pflag.String("network", "tcp", "network to dial")
address := pflag.String("address", "127.0.0.1:30012", "address to dial")
loglevel := pflag.String("loglevel", "info", "log level, trace debug info warn error")
count := pflag.Int("count", 10000, "edges to dial")
topic := pflag.String("topic", "test", "topic to specific")
nseconds := pflag.Int("nseconds", 10, "publish message every n seconds for every edge")
msg := pflag.String("msg", "testtesttest", "the message content to publish")
sourceIPs := pflag.String("source_ips", "", "source ips to dial, if you want dial more than \"65535\" source ports")
pprof := pflag.String("pprof", "", "pprof addr to listen")
pflag.Parse()
if *pprof != "" {
go func() {
http.ListenAndServe(*pprof, nil)
}()
}
ips := []string{}
idx := int64(0)
if *sourceIPs != "" {
ips = strings.Split(*sourceIPs, ",")
idx = 0
}
dialer := func() (net.Conn, error) {
if len(ips) != 0 {
for retry := 0; retry < 3; retry++ {
thisidx := atomic.LoadInt64(&idx)
ip := ips[int(thisidx)%len(ips)]
localAddr := &net.TCPAddr{
IP: net.ParseIP(ip),
}
dialer := &net.Dialer{
LocalAddr: localAddr,
Timeout: 5 * time.Second,
}
conn, err := dialer.Dial(*network, *address)
if err == nil {
return conn, nil
}
if strings.Contains(err.Error(), "cannot assign requested address") ||
strings.Contains(err.Error(), "address already in use") {
atomic.AddInt64(&idx, 1)
continue
}
fmt.Printf("unknown dial err: %s, source ip: %s:%d \n", err, localAddr.IP.String(), localAddr.Port)
return nil, err
}
}
return net.Dial(*network, *address)
}
// log
level, err := armlog.ParseLevel(*loglevel)
if err != nil {
fmt.Println("parse log level err:", err)
return
}
armlog.SetLevel(level)
armlog.SetOutput(os.Stdout)
wg := sync.WaitGroup{}
wg.Add(*count)
tmr := timer.NewTimer()
for i := 0; i < *count; i++ {
go func(i int) {
defer wg.Done()
// avoid congestion of connection
n := *count / 100
if n == 0 {
n = 1
}
random := rand.Intn(n) + 1
time.Sleep(time.Second * time.Duration(random))
// new edge connection
cli, err := edge.NewEdge(dialer,
edge.OptionEdgeLog(armlog.DefaultLog),
edge.OptionEdgeTimer(tmr),
edge.OptionServiceBufferSize(128, 128))
if err != nil {
armlog.Info("new edge err:", err)
return
}
mtx.Lock()
edges[i] = cli
mtx.Unlock()
// publish message in loop
for {
gmsg := cli.NewMessage([]byte(*msg))
err := cli.Publish(context.TODO(), *topic, gmsg)
if err != nil {
fmt.Println("publish err", err)
break
}
time.Sleep(time.Duration(*nseconds) * time.Second)
}
mtx.Lock()
delete(edges, i)
mtx.Unlock()
cli.Close()
}(i)
}
go func() {
ticker := time.NewTicker(time.Second * 10)
for {
<-ticker.C
mtx.RLock()
online := len(edges)
mtx.RUnlock()
fmt.Printf("online: %d\n", online)
}
}()
sig := sigaction.NewSignal()
sig.Wait(context.TODO())
mtx.RLock()
for _, edge := range edges {
edge.Close()
}
mtx.RUnlock()
}