add background context
diff --git a/mirko.go b/mirko.go
index 417e45d..6ce91fa 100644
--- a/mirko.go
+++ b/mirko.go
@@ -6,6 +6,8 @@
"fmt"
"net"
"net/http"
+ "os"
+ "os/signal"
"time"
"code.hackerspace.pl/q3k/hspki"
@@ -35,10 +37,19 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}()
+ 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: