Skip to content

Commit

Permalink
Merge pull request #21 from kffl/feat/lib-api-improvements
Browse files Browse the repository at this point in the history
feat!: `lib` API improvements
  • Loading branch information
kffl authored Aug 10, 2022
2 parents 9a4fb6d + e63eee6 commit a4e38c6
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 35 deletions.
2 changes: 1 addition & 1 deletion args.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func parseArgs(args []string) (*lib.SpeedbumpCfg, error) {
String()
)

app.Version("0.2.0")
app.Version("1.0.0")
_, err := app.Parse(args)

if err != nil {
Expand Down
27 changes: 17 additions & 10 deletions lib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ func main() {
Port: 8000,
DestAddr: "localhost:80",
BufferSize: 16384,
QueueSize: 2048,
QueueSize: 2048,
Latency: &speedbump.LatencyCfg{
Base: time.Millisecond * 100,
SineAmplitude: time.Millisecond * 50,
SinePeriod: time.Minute,
},
LogLevel: "INFO",
LogLevel: "TRACE",
}

s, err := speedbump.NewSpeedbump(&cfg)
Expand All @@ -44,22 +44,29 @@ func main() {
return
}

go func() {
// stop the proxy after 5 minutes
time.Sleep(time.Second * 5)
s.Stop()
}()

// Start() will either block until .Stop() is called
// or return immedietely if there is a startup error
// Start() will unblock as soon as the proxy is started
// or return an error if there is a startup error
err = s.Start()

if err != nil {
// handle startup error
return
}

// let's stop the proxy after 5 mins
time.Sleep(time.Minute * 5)

s.Stop()

// DONE
}

```

## `v1` Upgrade guide

In an effort to make the `lib` package easier to work with when used as a dependency for Go tests, the following changes were made to its API in the `v1` release:

- `Start()` is no longer blocking. It will either unblock as soon as the proxy starts listening or return an error if proxy startup fails;
- `Stop()` waits for all proxy connections to close before returning;
- a field name typo `sawAmplitute` was fixed in `LatencyCfg` struct (renamed to `SawAmplitude`).
18 changes: 8 additions & 10 deletions lib/speedbump.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,8 @@ func (s *Speedbump) startProxyConnection(p *connection) {
p.start()
}

// Start launches a Speedbump instance. This operation will either block
// until all proxy connections are closed following a Stop() call or
// return immedietely if a ListenTCP error occurrs at startup.
// Start launches a Speedbump instance. This operation will unblock either
// as soon as the proxy starts listening or when a startup error occurrs.
func (s *Speedbump) Start() error {
listener, err := net.ListenTCP("tcp", &s.srcAddr)
if err != nil {
Expand All @@ -130,21 +129,20 @@ func (s *Speedbump) Start() error {

s.log.Info("Started speedbump", "port", s.srcAddr.Port, "dest", s.destAddr.String())

// startAcceptLoop will block until Stop() is called
s.startAcceptLoop()
s.log.Debug("Waiting for active connections to be closed")
s.active.Wait()
s.log.Info("Speedbump stopped")
go s.startAcceptLoop()
return nil
}

// Stop closes the Speedbump instance's TCP listener and notifies all existing
// proxy connections that Speedbump is shutting down. It doesn't wait for
// the individual proxy connections to close prior to returning.
// proxy connections that Speedbump is shutting down. It waits for individual
// proxy connections to close before returning.
func (s *Speedbump) Stop() {
s.log.Info("Stopping speedbump")
// close TCP listener so that startAcceptLoop returns
s.listener.Close()
// notify all proxy connections
s.ctxCancel()
s.log.Debug("Waiting for active connections to be closed")
s.active.Wait()
s.log.Info("Speedbump stopped")
}
17 changes: 4 additions & 13 deletions lib/speedbump_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,24 +135,15 @@ func TestSpeedbumpWithEchoServer(t *testing.T) {
"WARN",
}
s, err := NewSpeedbump(&cfg)
go s.Start()
s.Start()

assert.Nil(t, err)

tcpAddr, _ := net.ResolveTCPAddr("tcp", "localhost:8000")

var conn *net.TCPConn

// Wait for the speedbump instance to start listening
// since it is started in a separate goroutine, we don't know
// if it has already started listening by this point
for {
conn, err = net.DialTCP("tcp", nil, tcpAddr)
if err != nil {
time.Sleep(10 * time.Millisecond)
} else {
break
}
conn, err := net.DialTCP("tcp", nil, tcpAddr)
if err != nil {
panic(err)
}

firstOpStart := time.Now()
Expand Down
13 changes: 12 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,19 @@ func main() {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

done := make(chan bool)

go func() {
<-sigs
go s.Stop()
// signal was caught for the first time
// stop the speedbump instance
go func() {
s.Stop()
done <- true
}()
<-sigs
// signal was caught for the second time
// force the process to exit
os.Exit(1)
}()

Expand All @@ -42,4 +51,6 @@ func main() {
if err != nil {
exitWithError(err)
}

<-done
}

0 comments on commit a4e38c6

Please sign in to comment.