add background context

master
Serge Bazanski 2018-10-14 18:20:59 +01:00
parent c99e0b9166
commit 4f7ee51e9a
2 changed files with 48 additions and 2 deletions

4
README
View File

@ -32,8 +32,10 @@ Usage (dev)
}
// start any other background processing...
// (you can use m.Context() to get a context that will get
// canceled when the service is about to shut down)
select {}
<-m.Done()
}
Usage (running)

View File

@ -6,6 +6,8 @@ import (
"fmt"
"net"
"net/http"
"os"
"os/signal"
"time"
"code.hackerspace.pl/q3k/hspki"
@ -35,10 +37,19 @@ type Mirko struct {
httpListen net.Listener
httpServer *http.Server
httpMux *http.ServeMux
ctx context.Context
cancel context.CancelFunc
waiters []chan bool
}
func New() *Mirko {
return &Mirko{}
ctx, cancel := context.WithCancel(context.Background())
return &Mirko{
ctx: ctx,
cancel: cancel,
waiters: []chan bool{},
}
}
func authRequest(req *http.Request) (any, sensitive bool) {
@ -113,6 +124,8 @@ func (m *Mirko) Listen() error {
return nil
}
// Trace logs debug information to either a context trace (if present)
// or stderr (if not)
func Trace(ctx context.Context, f string, args ...interface{}) {
tr, ok := trace.FromContext(ctx)
if !ok {
@ -123,6 +136,7 @@ func Trace(ctx context.Context, f string, args ...interface{}) {
tr.LazyPrintf(f, args...)
}
// GRPC returns the microservice's grpc.Server object
func (m *Mirko) GRPC() *grpc.Server {
if m.grpcServer == nil {
panic("GRPC() called before Listen()")
@ -130,6 +144,7 @@ func (m *Mirko) GRPC() *grpc.Server {
return m.grpcServer
}
// HTTPMux returns the microservice's debug HTTP mux
func (m *Mirko) HTTPMux() *http.ServeMux {
if m.httpMux == nil {
panic("HTTPMux() called before Listen()")
@ -137,6 +152,22 @@ func (m *Mirko) HTTPMux() *http.ServeMux {
return m.httpMux
}
// Context returns a background microservice context that will be canceled
// when the service is shut down
func (m *Mirko) Context() context.Context {
return m.ctx
}
// Done() returns a channel that will emit a value when the service is
// shut down. This should be used in the main() function instead of a select{}
// call, to allow the background context to be canceled fully.
func (m *Mirko) Done() chan bool {
c := make(chan bool, 1)
m.waiters = append(m.waiters, c)
return c
}
// Serve starts serving HTTP and gRPC requests
func (m *Mirko) Serve() error {
errs := make(chan error, 1)
go func() {
@ -150,6 +181,19 @@ func (m *Mirko) Serve() error {
}
}()
signalCh := make(chan os.Signal, 1)
signal.Notify(signalCh, os.Interrupt)
go func() {
select {
case <-signalCh:
m.cancel()
time.Sleep(time.Second)
for _, w := range m.waiters {
w <- true
}
}
}()
ticker := time.NewTicker(1 * time.Second)
select {
case <-ticker.C: