Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Shutdown() and ShutdownWithContext() #103

Merged
merged 4 commits into from
Sep 6, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions atreugo.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package atreugo

import (
"context"
"log"
"net"
"os"
Expand Down Expand Up @@ -272,3 +273,25 @@

return vHost
}

// Shutdown gracefully shuts down the server without interrupting any active connections.
// Shutdown works by first closing all open listeners and then waiting indefinitely for all connections to return to idle and then shut down.

Check failure on line 278 in atreugo.go

View workflow job for this annotation

GitHub Actions / lint

line is 141 characters (lll)
//
// When Shutdown is called, Serve, ListenAndServe, and ListenAndServeTLS immediately return nil.
// Make sure the program doesn't exit and waits instead for Shutdown to return.
//
// Shutdown does not close keepalive connections so it's recommended to set ReadTimeout and IdleTimeout to something else than 0.

Check failure on line 283 in atreugo.go

View workflow job for this annotation

GitHub Actions / lint

line is 129 characters (lll)
func (s *Atreugo) Shutdown() error {
return s.engine.Shutdown()

Check failure on line 285 in atreugo.go

View workflow job for this annotation

GitHub Actions / lint

error returned from external package is unwrapped: sig: func (*github.com/valyala/fasthttp.Server).Shutdown() error (wrapcheck)
}

// ShutdownWithContext gracefully shuts down the server without interrupting any active connections.
// ShutdownWithContext works by first closing all open listeners and then waiting for all connections to return to idle or context timeout and then shut down.

Check failure on line 289 in atreugo.go

View workflow job for this annotation

GitHub Actions / lint

line is 158 characters (lll)
//
// When ShutdownWithContext is called, Serve, ListenAndServe, and ListenAndServeTLS immediately return nil.
// Make sure the program doesn't exit and waits instead for Shutdown to return.
//
// ShutdownWithContext does not close keepalive connections so it's recommended to set ReadTimeout and IdleTimeout to something else than 0.

Check failure on line 294 in atreugo.go

View workflow job for this annotation

GitHub Actions / lint

line is 140 characters (lll)
func (s *Atreugo) ShutdownWithContext(ctx context.Context) error {
return s.engine.ShutdownWithContext(ctx)

Check failure on line 296 in atreugo.go

View workflow job for this annotation

GitHub Actions / lint

error returned from external package is unwrapped: sig: func (*github.com/valyala/fasthttp.Server).ShutdownWithContext(ctx context.Context) (err error) (wrapcheck)
}
72 changes: 72 additions & 0 deletions atreugo_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package atreugo

import (
"context"
"crypto/tls"
"errors"
"fmt"
Expand Down Expand Up @@ -591,6 +592,77 @@ func TestAtreugo_NewVirtualHost(t *testing.T) { //nolint:funlen
}
}

func TestAtreugo_Shutdown(t *testing.T) {
s := New(testConfig)

ln := fasthttputil.NewInmemoryListener()
errCh := make(chan error, 1)

go func() {
errCh <- s.Serve(ln)
}()

time.Sleep(500 * time.Millisecond)

if err := s.Shutdown(); err != nil {
t.Fatalf("Unexpected error: %v", err)
}

if err := <-errCh; err != nil {
t.Fatalf("Unexpected error: %v", err)
}

if lnAddr := ln.Addr().String(); s.cfg.Addr != lnAddr {
t.Errorf("Atreugo.Config.Addr = %s, want %s", s.cfg.Addr, lnAddr)
}

lnNetwork := ln.Addr().Network()
if s.cfg.Network != lnNetwork {
t.Errorf("Atreugo.Config.Network = %s, want %s", s.cfg.Network, lnNetwork)
}

if s.engine.Handler == nil {
t.Error("Atreugo.engine.Handler is nil")
}
}

func TestAtreugo_ShutdownWithContext(t *testing.T) {
s := New(testConfig)

ln := fasthttputil.NewInmemoryListener()
errCh := make(chan error, 1)

go func() {
errCh <- s.Serve(ln)
}()

time.Sleep(500 * time.Millisecond)

ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
defer cancel()

if err := s.ShutdownWithContext(ctx); err != nil {
t.Fatalf("Unexpected error: %v", err)
}

if err := <-errCh; err != nil {
t.Fatalf("Unexpected error: %v", err)
}

if lnAddr := ln.Addr().String(); s.cfg.Addr != lnAddr {
t.Errorf("Atreugo.Config.Addr = %s, want %s", s.cfg.Addr, lnAddr)
}

lnNetwork := ln.Addr().Network()
if s.cfg.Network != lnNetwork {
t.Errorf("Atreugo.Config.Network = %s, want %s", s.cfg.Network, lnNetwork)
}

if s.engine.Handler == nil {
t.Error("Atreugo.engine.Handler is nil")
}
}

// Benchmarks.
func Benchmark_Handler(b *testing.B) {
s := New(testConfig)
Expand Down
Loading