Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
golib
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Gaia-X
Trust Services API
golib
Commits
854b152c
Commit
854b152c
authored
3 years ago
by
Lyuben Penkovski
Browse files
Options
Downloads
Patches
Plain Diff
Add package for graceful shutdown of HTTP servers
parent
3c89eed5
Branches
Branches containing commit
Tags
Tags containing commit
1 merge request
!4
Add package for graceful shutdown of HTTP servers
Pipeline
#49426
passed
3 years ago
Stage: test
Changes
4
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
.gitlab-ci.yml
+2
-2
2 additions, 2 deletions
.gitlab-ci.yml
README.md
+1
-1
1 addition, 1 deletion
README.md
graceful/graceful.go
+45
-0
45 additions, 0 deletions
graceful/graceful.go
graceful/graceful_test.go
+183
-0
183 additions, 0 deletions
graceful/graceful_test.go
with
231 additions
and
3 deletions
.gitlab-ci.yml
+
2
−
2
View file @
854b152c
...
...
@@ -6,7 +6,7 @@ before_script:
-
cd /go/src/code.vereign.com/${CI_PROJECT_PATH}
unit tests
:
image
:
golang:1.17.
7
image
:
golang:1.17.
8
stage
:
test
tags
:
-
amd64-docker
...
...
@@ -16,7 +16,7 @@ unit tests:
-
go tool cover -func=coverage.out
lint
:
image
:
golangci/golangci-lint:v1.4
4.2
image
:
golangci/golangci-lint:v1.4
5.0
stage
:
test
tags
:
-
amd64-docker
...
...
This diff is collapsed.
Click to expand it.
README.md
+
1
−
1
View file @
854b152c
...
...
@@ -3,4 +3,4 @@
# golib
Go library with utility packages shared across multiple services.
\ No newline at end of file
Go library with utility packages used in TSA backend services.
\ No newline at end of file
This diff is collapsed.
Click to expand it.
graceful/graceful.go
0 → 100644
+
45
−
0
View file @
854b152c
package
graceful
import
(
"context"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
// Shutdown gracefully stops the given HTTP server on
// receiving a stop signal or context cancellation signal
// and waits for the active connections to be closed
// for {timeout} period of time.
//
// The {timeout} period is respected in both stop conditions.
func
Shutdown
(
ctx
context
.
Context
,
srv
*
http
.
Server
,
timeout
time
.
Duration
)
error
{
done
:=
make
(
chan
error
,
1
)
go
func
()
{
c
:=
make
(
chan
os
.
Signal
,
1
)
signal
.
Notify
(
c
,
os
.
Interrupt
,
syscall
.
SIGTERM
)
// wait for a signal or context cancellation
select
{
case
<-
c
:
case
<-
ctx
.
Done
()
:
}
ctx
:=
context
.
Background
()
var
cancel
context
.
CancelFunc
if
timeout
>
0
{
ctx
,
cancel
=
context
.
WithTimeout
(
ctx
,
timeout
)
defer
cancel
()
}
done
<-
srv
.
Shutdown
(
ctx
)
}()
if
err
:=
srv
.
ListenAndServe
();
err
!=
nil
&&
err
!=
http
.
ErrServerClosed
{
return
err
}
return
<-
done
}
This diff is collapsed.
Click to expand it.
graceful/graceful_test.go
0 → 100644
+
183
−
0
View file @
854b152c
package
graceful_test
import
(
"context"
"errors"
"net/http"
"os"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"code.vereign.com/gaiax/tsa/golib/graceful"
)
type
handler
struct
{
requestTime
time
.
Duration
}
func
(
h
*
handler
)
ServeHTTP
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
time
.
Sleep
(
h
.
requestTime
)
}
func
TestShutdownWithSignal
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
// input
name
string
addr
string
timeout
time
.
Duration
reqTime
time
.
Duration
// desired outcome
err
error
maxShutdownDuration
time
.
Duration
}{
{
name
:
"without timeout"
,
addr
:
":58430"
,
timeout
:
0
,
reqTime
:
200
*
time
.
Millisecond
,
err
:
nil
,
maxShutdownDuration
:
250
*
time
.
Millisecond
,
},
{
name
:
"with timeout higher than request processing time"
,
addr
:
":58431"
,
timeout
:
500
*
time
.
Millisecond
,
reqTime
:
200
*
time
.
Millisecond
,
err
:
nil
,
maxShutdownDuration
:
250
*
time
.
Millisecond
,
},
{
name
:
"with timeout lower than request processing time"
,
addr
:
":58432"
,
timeout
:
50
*
time
.
Millisecond
,
reqTime
:
200
*
time
.
Millisecond
,
err
:
errors
.
New
(
"context deadline exceeded"
),
maxShutdownDuration
:
100
*
time
.
Millisecond
,
},
}
for
_
,
test
:=
range
tests
{
t
.
Run
(
test
.
name
,
func
(
t
*
testing
.
T
)
{
srv
:=
&
http
.
Server
{
Addr
:
test
.
addr
,
Handler
:
&
handler
{
requestTime
:
test
.
reqTime
},
}
reqerr
:=
make
(
chan
error
,
1
)
go
func
()
{
if
err
:=
graceful
.
Shutdown
(
context
.
Background
(),
srv
,
test
.
timeout
);
err
!=
nil
{
reqerr
<-
err
}
}()
go
func
()
{
_
,
err
:=
http
.
Get
(
"http://localhost"
+
test
.
addr
)
reqerr
<-
err
}()
// wait a while so the HTTP request could be sent
time
.
Sleep
(
50
*
time
.
Millisecond
)
start
:=
time
.
Now
()
proc
,
err
:=
os
.
FindProcess
(
os
.
Getpid
())
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
proc
.
Signal
(
os
.
Interrupt
))
err
=
<-
reqerr
if
test
.
err
!=
nil
{
assert
.
EqualError
(
t
,
err
,
test
.
err
.
Error
())
}
else
{
assert
.
NoError
(
t
,
err
)
}
assert
.
True
(
t
,
time
.
Since
(
start
)
<
test
.
maxShutdownDuration
)
})
}
}
func
TestShutdownWithContext
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
// input
name
string
contextTimeout
time
.
Duration
addr
string
timeout
time
.
Duration
reqTime
time
.
Duration
// desired outcome
err
error
maxShutdownDuration
time
.
Duration
}{
{
name
:
"with context timeout higher than request processing time"
,
addr
:
":58431"
,
contextTimeout
:
500
*
time
.
Millisecond
,
reqTime
:
200
*
time
.
Millisecond
,
err
:
nil
,
maxShutdownDuration
:
250
*
time
.
Millisecond
,
},
{
name
:
"context timeout lower than request processing time"
,
addr
:
":58432"
,
timeout
:
10
*
time
.
Millisecond
,
contextTimeout
:
100
*
time
.
Millisecond
,
reqTime
:
300
*
time
.
Millisecond
,
err
:
errors
.
New
(
"context deadline exceeded"
),
maxShutdownDuration
:
150
*
time
.
Millisecond
,
},
}
for
_
,
test
:=
range
tests
{
t
.
Run
(
test
.
name
,
func
(
t
*
testing
.
T
)
{
srv
:=
&
http
.
Server
{
Addr
:
test
.
addr
,
Handler
:
&
handler
{
requestTime
:
test
.
reqTime
},
}
ctx
:=
context
.
Background
()
var
cancel
context
.
CancelFunc
if
test
.
contextTimeout
>
0
{
ctx
,
cancel
=
context
.
WithTimeout
(
ctx
,
test
.
contextTimeout
)
defer
cancel
()
}
reqerr
:=
make
(
chan
error
,
1
)
go
func
()
{
if
err
:=
graceful
.
Shutdown
(
ctx
,
srv
,
test
.
timeout
);
err
!=
nil
{
reqerr
<-
err
}
}()
go
func
()
{
_
,
err
:=
http
.
Get
(
"http://localhost"
+
test
.
addr
)
reqerr
<-
err
}()
start
:=
time
.
Now
()
// wait a while so the HTTP request could be sent
time
.
Sleep
(
50
*
time
.
Millisecond
)
err
:=
<-
reqerr
if
test
.
err
!=
nil
{
assert
.
EqualError
(
t
,
err
,
test
.
err
.
Error
())
}
else
{
assert
.
NoError
(
t
,
err
)
}
assert
.
True
(
t
,
time
.
Since
(
start
)
<
test
.
maxShutdownDuration
)
})
}
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment