1
0
mirror of https://github.com/mainflux/mainflux.git synced 2025-04-24 13:48:49 +08:00

MF-1525 - Add graceful stop for HTTP and GRPC servers (#1548)

* Add : errgroup to cmd/auth

Signed-off-by: Arvindh <arvindh91@gmail.com>

* Add : Handle graceful stop for auth service
Remove : errgroups from auth service

Signed-off-by: Arvindh <arvindh91@gmail.com>

* Add : Wait till server shutdown

Signed-off-by: Arvindh <arvindh91@gmail.com>

* Change : instead of waitgroup changed to errgroups

Signed-off-by: Arvindh <arvindh91@gmail.com>

* change : KillSignalHandler return type to error

Signed-off-by: Arvindh <arvindh91@gmail.com>

* Empty Commit

Signed-off-by: Arvindh <arvindh91@gmail.com>

* Add : Context to http server shutdown
Rename : varaible from proto to protocol

Signed-off-by: Arvindh <arvindh91@gmail.com>

* change : to default log level

Signed-off-by: Arvindh <arvindh91@gmail.com>

* Add : Sign-off

Signed-off-by: Arvindh <arvindh91@gmail.com>

* Add: graceful stop of http and grpc server

Signed-off-by: Arvindh <arvindh91@gmail.com>

* Fix: typos and caps

Signed-off-by: Arvindh <arvindh91@gmail.com>

* Add: Signed-off

Signed-off-by: Arvindh <arvindh91@gmail.com>

* Rename: Func KillSignalHandler to SignalHandler
Add: SIGABRT

Signed-off-by: Arvindh <arvindh91@gmail.com>

* Fix: auth service

Signed-off-by: Arvindh <arvindh91@gmail.com>

* Add: timeout for grpc gracefulstop
Fix: typos

Signed-off-by: Arvindh <arvindh91@gmail.com>

* Add: .vscode folder to git ignore

Signed-off-by: Arvindh <arvindh91@gmail.com>

* change: variable name to stopWaitTime

Signed-off-by: Arvindh <arvindh91@gmail.com>

* remove: .vscode folder

Signed-off-by: Arvindh <arvindh91@gmail.com>

* remove: .vscode from .gitignore

Signed-off-by: Arvindh <arvindh91@gmail.com>

* Add : logger to handlers

Signed-off-by: Arvindh <arvindh91@gmail.com>

* Add : New line at end of .gitignore file

Signed-off-by: Arvindh <arvindh91@gmail.com>

* Fix : variable naming
Add : graceful stop for timescale

Signed-off-by: Arvindh <arvindh91@gmail.com>

* Remove : unsued NATS library from import

Signed-off-by: Arvindh <arvindh91@gmail.com>

* Move: "https" and "https" to moved to const var

Signed-off-by: Arvindh <arvindh91@gmail.com>

* Move: "http" and "https" to moved to const var

Signed-off-by: Arvindh <arvindh91@gmail.com>

* update:  branch with master

Signed-off-by: Arvindh <arvindh91@gmail.com>

Co-authored-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>
Co-authored-by: Drasko DRASKOVIC <drasko.draskovic@gmail.com>
This commit is contained in:
Arvindh 2022-05-03 17:27:54 +05:30 committed by GitHub
parent 195b78303f
commit b19ba0db7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 1203 additions and 418 deletions

1
.gitignore vendored
View File

@ -5,4 +5,3 @@
# https://digitalfortress.tech/tricks/creating-a-global-gitignore/
build

View File

@ -1,6 +1,7 @@
package main
import (
"context"
"fmt"
"io"
"io/ioutil"
@ -8,8 +9,6 @@ import (
"net"
"net/http"
"os"
"os/signal"
"syscall"
"time"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
@ -24,16 +23,22 @@ import (
"github.com/mainflux/mainflux/auth/postgres"
"github.com/mainflux/mainflux/auth/tracing"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/pkg/uuid"
"github.com/opentracing/opentracing-go"
acl "github.com/ory/keto/proto/ory/keto/acl/v1alpha1"
stdprometheus "github.com/prometheus/client_golang/prometheus"
jconfig "github.com/uber/jaeger-client-go/config"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
const (
stopWaitTime = 5 * time.Second
httpProtocol = "http"
httpsProtocol = "https"
defLogLevel = "error"
defDBHost = "localhost"
defDBPort = "5432"
@ -103,7 +108,8 @@ type tokenConfig struct {
func main() {
cfg := loadConfig()
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
logger, err := logger.New(os.Stdout, cfg.logLevel)
if err != nil {
log.Fatalf(err.Error())
@ -121,19 +127,24 @@ func main() {
readerConn, writerConn := initKeto(cfg.ketoReadHost, cfg.ketoReadPort, cfg.ketoWriteHost, cfg.ketoWritePort, logger)
svc := newService(db, dbTracer, cfg.secret, logger, readerConn, writerConn, cfg.loginDuration)
errs := make(chan error, 2)
go startHTTPServer(tracer, svc, cfg.httpPort, cfg.serverCert, cfg.serverKey, logger, errs)
go startGRPCServer(tracer, svc, cfg.grpcPort, cfg.serverCert, cfg.serverKey, logger, errs)
g.Go(func() error {
return startHTTPServer(ctx, tracer, svc, cfg.httpPort, cfg.serverCert, cfg.serverKey, logger)
})
g.Go(func() error {
return startGRPCServer(ctx, tracer, svc, cfg.grpcPort, cfg.serverCert, cfg.serverKey, logger)
})
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
err = <-errs
logger.Error(fmt.Sprintf("Authentication service terminated: %s", err))
g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("Authentication service shutdown by signal: %s", sig))
}
return nil
})
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("Authentication service terminated: %s", err))
}
}
func loadConfig() config {
@ -254,40 +265,83 @@ func newService(db *sqlx.DB, tracer opentracing.Tracer, secret string, logger lo
return svc
}
func startHTTPServer(tracer opentracing.Tracer, svc auth.Service, port string, certFile string, keyFile string, logger logger.Logger, errs chan error) {
func startHTTPServer(ctx context.Context, tracer opentracing.Tracer, svc auth.Service, port string, certFile string, keyFile string, logger logger.Logger) error {
p := fmt.Sprintf(":%s", port)
if certFile != "" || keyFile != "" {
server := &http.Server{Addr: p, Handler: httpapi.MakeHandler(svc, tracer, logger)}
errCh := make(chan error)
protocol := httpProtocol
switch {
case certFile != "" || keyFile != "":
logger.Info(fmt.Sprintf("Authentication service started using https, cert %s key %s, exposed port %s", certFile, keyFile, port))
errs <- http.ListenAndServeTLS(p, certFile, keyFile, httpapi.MakeHandler(svc, tracer, logger))
return
go func() {
errCh <- server.ListenAndServeTLS(certFile, keyFile)
}()
protocol = httpsProtocol
default:
logger.Info(fmt.Sprintf("Authentication service started using http, exposed port %s", port))
go func() {
errCh <- server.ListenAndServe()
}()
}
logger.Info(fmt.Sprintf("Authentication service started using http, exposed port %s", port))
errs <- http.ListenAndServe(p, httpapi.MakeHandler(svc, tracer, logger))
select {
case <-ctx.Done():
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
defer cancelShutdown()
if err := server.Shutdown(ctxShutdown); err != nil {
logger.Error(fmt.Sprintf("Authentication %s service error occurred during shutdown at %s: %s", protocol, p, err))
return fmt.Errorf("Authentication %s service error occurred during shutdown at %s: %w", protocol, p, err)
}
logger.Info(fmt.Sprintf("Authentication %s service shutdown of http at %s", protocol, p))
return nil
case err := <-errCh:
return err
}
}
func startGRPCServer(tracer opentracing.Tracer, svc auth.Service, port string, certFile string, keyFile string, logger logger.Logger, errs chan error) {
func startGRPCServer(ctx context.Context, tracer opentracing.Tracer, svc auth.Service, port string, certFile string, keyFile string, logger logger.Logger) error {
p := fmt.Sprintf(":%s", port)
errCh := make(chan error)
listener, err := net.Listen("tcp", p)
if err != nil {
logger.Error(fmt.Sprintf("Failed to listen on port %s: %s", port, err))
return fmt.Errorf("failed to listen on port %s: %w", port, err)
}
var server *grpc.Server
if certFile != "" || keyFile != "" {
switch {
case certFile != "" || keyFile != "":
creds, err := credentials.NewServerTLSFromFile(certFile, keyFile)
if err != nil {
logger.Error(fmt.Sprintf("Failed to load auth certificates: %s", err))
os.Exit(1)
return fmt.Errorf("failed to load auth certificates: %w", err)
}
logger.Info(fmt.Sprintf("Authentication gRPC service started using https on port %s with cert %s key %s", port, certFile, keyFile))
server = grpc.NewServer(grpc.Creds(creds))
} else {
default:
logger.Info(fmt.Sprintf("Authentication gRPC service started using http on port %s", port))
server = grpc.NewServer()
}
mainflux.RegisterAuthServiceServer(server, grpcapi.NewServer(tracer, svc))
logger.Info(fmt.Sprintf("Authentication gRPC service started, exposed port %s", port))
errs <- server.Serve(listener)
go func() {
errCh <- server.Serve(listener)
}()
select {
case <-ctx.Done():
c := make(chan bool)
go func() {
defer close(c)
server.GracefulStop()
}()
select {
case <-c:
case <-time.After(stopWaitTime):
}
logger.Info(fmt.Sprintf("Authentication gRPC service shutdown at %s", p))
return nil
case err := <-errCh:
return err
}
}

View File

@ -12,9 +12,7 @@ import (
"log"
"net/http"
"os"
"os/signal"
"strconv"
"syscall"
"time"
authapi "github.com/mainflux/mainflux/auth/api/grpc"
@ -22,6 +20,7 @@ import (
redisprod "github.com/mainflux/mainflux/bootstrap/redis/producer"
"github.com/mainflux/mainflux/logger"
opentracing "github.com/opentracing/opentracing-go"
"golang.org/x/sync/errgroup"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
r "github.com/go-redis/redis/v8"
@ -31,6 +30,7 @@ import (
api "github.com/mainflux/mainflux/bootstrap/api"
"github.com/mainflux/mainflux/bootstrap/postgres"
mflog "github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
mfsdk "github.com/mainflux/mainflux/pkg/sdk/go"
stdprometheus "github.com/prometheus/client_golang/prometheus"
jconfig "github.com/uber/jaeger-client-go/config"
@ -39,6 +39,10 @@ import (
)
const (
stopWaitTime = 5 * time.Second
httpProtocol = "http"
httpsProtocol = "https"
defLogLevel = "error"
defDBHost = "localhost"
defDBPort = "5432"
@ -123,6 +127,8 @@ type config struct {
func main() {
cfg := loadConfig()
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
logger, err := mflog.New(os.Stdout, cfg.logLevel)
if err != nil {
@ -147,19 +153,24 @@ func main() {
auth := authapi.NewClient(authTracer, authConn, cfg.authTimeout)
svc := newService(auth, db, logger, esClient, cfg)
errs := make(chan error, 2)
go startHTTPServer(svc, cfg, logger, errs)
g.Go(func() error {
return startHTTPServer(ctx, svc, cfg, logger)
})
go subscribeToThingsES(svc, thingsESConn, cfg.esConsumerName, logger)
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("Bootstrap service shutdown by signal: %s", sig))
}
return nil
})
err = <-errs
logger.Error(fmt.Sprintf("Bootstrap service terminated: %s", err))
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("Bootstrap service terminated: %s", err))
}
}
func loadConfig() config {
@ -320,16 +331,40 @@ func connectToAuth(cfg config, logger logger.Logger) *grpc.ClientConn {
return conn
}
func startHTTPServer(svc bootstrap.Service, cfg config, logger mflog.Logger, errs chan error) {
func startHTTPServer(ctx context.Context, svc bootstrap.Service, cfg config, logger mflog.Logger) error {
p := fmt.Sprintf(":%s", cfg.httpPort)
if cfg.serverCert != "" || cfg.serverKey != "" {
server := &http.Server{Addr: p, Handler: api.MakeHandler(svc, bootstrap.NewConfigReader(cfg.encKey), logger)}
errCh := make(chan error)
protocol := httpProtocol
switch {
case cfg.serverCert != "" || cfg.serverKey != "":
logger.Info(fmt.Sprintf("Bootstrap service started using https on port %s with cert %s key %s",
cfg.httpPort, cfg.serverCert, cfg.serverKey))
errs <- http.ListenAndServeTLS(p, cfg.serverCert, cfg.serverKey, api.MakeHandler(svc, bootstrap.NewConfigReader(cfg.encKey), logger))
return
go func() {
errCh <- server.ListenAndServeTLS(cfg.serverCert, cfg.serverKey)
}()
protocol = httpsProtocol
default:
logger.Info(fmt.Sprintf("Bootstrap service started using http on port %s", cfg.httpPort))
go func() {
errCh <- server.ListenAndServe()
}()
}
select {
case <-ctx.Done():
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
defer cancelShutdown()
if err := server.Shutdown(ctxShutdown); err != nil {
logger.Error(fmt.Sprintf("Bootstrap %s service error occurred during shutdown at %s: %s", protocol, p, err))
return fmt.Errorf("bootstrap %s service error occurred during shutdown at %s: %w", protocol, p, err)
}
logger.Info(fmt.Sprintf("Bootstrap %s service shutdown of http at %s", protocol, p))
return nil
case err := <-errCh:
return err
}
logger.Info(fmt.Sprintf("Bootstrap service started using http on port %s", cfg.httpPort))
errs <- http.ListenAndServe(p, api.MakeHandler(svc, bootstrap.NewConfigReader(cfg.encKey), logger))
}
func subscribeToThingsES(svc bootstrap.Service, client *r.Client, consumer string, logger mflog.Logger) {

View File

@ -4,16 +4,15 @@
package main
import (
"context"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
"time"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
@ -21,6 +20,7 @@ import (
"github.com/mainflux/mainflux"
authapi "github.com/mainflux/mainflux/auth/api/grpc"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/readers"
"github.com/mainflux/mainflux/readers/api"
"github.com/mainflux/mainflux/readers/cassandra"
@ -28,11 +28,14 @@ import (
opentracing "github.com/opentracing/opentracing-go"
stdprometheus "github.com/prometheus/client_golang/prometheus"
jconfig "github.com/uber/jaeger-client-go/config"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
const (
stopWaitTime = 5 * time.Second
svcName = "cassandra-reader"
sep = ","
defLogLevel = "error"
@ -87,6 +90,8 @@ type config struct {
func main() {
cfg := loadConfig()
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
logger, err := logger.New(os.Stdout, cfg.logLevel)
if err != nil {
@ -113,18 +118,20 @@ func main() {
repo := newService(session, logger)
errs := make(chan error, 2)
g.Go(func() error {
return startHTTPServer(ctx, repo, tc, auth, cfg, logger)
})
go startHTTPServer(repo, tc, auth, cfg, errs, logger)
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
err = <-errs
logger.Error(fmt.Sprintf("Cassandra reader service terminated: %s", err))
g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("Cassandra reader service shutdown by signal: %s", sig))
}
return nil
})
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("Cassandra reader service terminated: %s", err))
}
}
func connectToAuth(cfg config, logger logger.Logger) *grpc.ClientConn {
@ -279,14 +286,33 @@ func newService(session *gocql.Session, logger logger.Logger) readers.MessageRep
return repo
}
func startHTTPServer(repo readers.MessageRepository, tc mainflux.ThingsServiceClient, ac mainflux.AuthServiceClient, cfg config, errs chan error, logger logger.Logger) {
func startHTTPServer(ctx context.Context, repo readers.MessageRepository, tc mainflux.ThingsServiceClient, ac mainflux.AuthServiceClient, cfg config, logger logger.Logger) error {
p := fmt.Sprintf(":%s", cfg.port)
if cfg.serverCert != "" || cfg.serverKey != "" {
logger.Info(fmt.Sprintf("Cassandra reader service started using https on port %s with cert %s key %s",
cfg.port, cfg.serverCert, cfg.serverKey))
errs <- http.ListenAndServeTLS(p, cfg.serverCert, cfg.serverKey, api.MakeHandler(repo, tc, ac, svcName, logger))
return
errCh := make(chan error)
server := &http.Server{Addr: p, Handler: api.MakeHandler(repo, tc, ac, "cassandra-reader", logger)}
switch {
case cfg.serverCert != "" || cfg.serverKey != "":
logger.Info(fmt.Sprintf("Cassandra reader service started using https on port %s with cert %s key %s", cfg.port, cfg.serverCert, cfg.serverKey))
go func() {
errCh <- server.ListenAndServeTLS(cfg.serverCert, cfg.serverKey)
}()
default:
logger.Info(fmt.Sprintf("Cassandra reader service started, exposed port %s", cfg.port))
go func() {
errCh <- server.ListenAndServe()
}()
}
select {
case <-ctx.Done():
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
defer cancelShutdown()
if err := server.Shutdown(ctxShutdown); err != nil {
logger.Error(fmt.Sprintf("Cassandra reader service error occurred during shutdown at %s: %s", p, err))
return fmt.Errorf("cassandra reader service error occurred during shutdown at %s: %w", p, err)
}
logger.Info(fmt.Sprintf("Cassandra reader service shutdown of http at %s", p))
return nil
case err := <-errCh:
return err
}
logger.Info(fmt.Sprintf("Cassandra reader service started, exposed port %s", cfg.port))
errs <- http.ListenAndServe(p, api.MakeHandler(repo, tc, ac, svcName, logger))
}

View File

@ -4,14 +4,14 @@
package main
import (
"context"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
"time"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
"github.com/gocql/gocql"
@ -20,13 +20,16 @@ import (
"github.com/mainflux/mainflux/consumers/writers/api"
"github.com/mainflux/mainflux/consumers/writers/cassandra"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/pkg/messaging/nats"
stdprometheus "github.com/prometheus/client_golang/prometheus"
"golang.org/x/sync/errgroup"
)
const (
svcName = "cassandra-writer"
sep = ","
svcName = "cassandra-writer"
sep = ","
stopWaitTime = 5 * time.Second
defNatsURL = "nats://localhost:4222"
defLogLevel = "error"
@ -59,6 +62,8 @@ type config struct {
func main() {
cfg := loadConfig()
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
logger, err := logger.New(os.Stdout, cfg.logLevel)
if err != nil {
@ -81,18 +86,19 @@ func main() {
logger.Error(fmt.Sprintf("Failed to create Cassandra writer: %s", err))
}
errs := make(chan error, 2)
go startHTTPServer(ctx, cfg.port, logger)
go startHTTPServer(cfg.port, errs, logger)
g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("Cassandra writer service shutdown by signal: %s", sig))
}
return nil
})
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
err = <-errs
logger.Error(fmt.Sprintf("Cassandra writer service terminated: %s", err))
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("Cassandra writer service terminated: %s", err))
}
}
func loadConfig() config {
@ -150,8 +156,26 @@ func newService(session *gocql.Session, logger logger.Logger) consumers.Consumer
return repo
}
func startHTTPServer(port string, errs chan error, logger logger.Logger) {
func startHTTPServer(ctx context.Context, port string, logger logger.Logger) error {
p := fmt.Sprintf(":%s", port)
errCh := make(chan error)
server := &http.Server{Addr: p, Handler: api.MakeHandler(svcName)}
logger.Info(fmt.Sprintf("Cassandra writer service started, exposed port %s", port))
errs <- http.ListenAndServe(p, api.MakeHandler(svcName))
go func() {
errCh <- server.ListenAndServe()
}()
select {
case <-ctx.Done():
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
defer cancelShutdown()
if err := server.Shutdown(ctxShutdown); err != nil {
logger.Error(fmt.Sprintf("Cassandra writer service error occurred during shutdown at %s: %s", p, err))
return fmt.Errorf("cassandra writer service error occurred during shutdown at %s: %w", p, err)
}
logger.Info(fmt.Sprintf("Cassandra writer service shutdown of http at %s", p))
return nil
case err := <-errCh:
return err
}
}

View File

@ -2,6 +2,7 @@
package main
import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/pem"
@ -11,9 +12,7 @@ import (
"log"
"net/http"
"os"
"os/signal"
"strconv"
"syscall"
"time"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
@ -27,6 +26,7 @@ import (
"github.com/mainflux/mainflux/logger"
"github.com/opentracing/opentracing-go"
stdprometheus "github.com/prometheus/client_golang/prometheus"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
@ -38,6 +38,8 @@ import (
)
const (
stopWaitTime = 5 * time.Second
defLogLevel = "error"
defDBHost = "localhost"
defDBPort = "5432"
@ -140,6 +142,8 @@ type config struct {
func main() {
cfg := loadConfig()
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
logger, err := mflog.New(os.Stdout, cfg.logLevel)
if err != nil {
@ -172,18 +176,22 @@ func main() {
auth := authapi.NewClient(authTracer, authConn, cfg.authTimeout)
svc := newService(auth, db, logger, nil, tlsCert, caCert, cfg, pkiClient)
errs := make(chan error, 2)
go startHTTPServer(svc, cfg, logger, errs)
g.Go(func() error {
return startHTTPServer(ctx, svc, cfg, logger)
})
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("Certs service shutdown by signal: %s", sig))
}
return nil
})
err = <-errs
logger.Error(fmt.Sprintf("Certs service terminated: %s", err))
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("Certs service terminated: %s", err))
}
}
func loadConfig() config {
@ -363,16 +371,36 @@ func newService(auth mainflux.AuthServiceClient, db *sqlx.DB, logger mflog.Logge
return svc
}
func startHTTPServer(svc certs.Service, cfg config, logger mflog.Logger, errs chan error) {
func startHTTPServer(ctx context.Context, svc certs.Service, cfg config, logger mflog.Logger) error {
p := fmt.Sprintf(":%s", cfg.httpPort)
if cfg.serverCert != "" || cfg.serverKey != "" {
logger.Info(fmt.Sprintf("Certs service started using https on port %s with cert %s key %s",
cfg.httpPort, cfg.serverCert, cfg.serverKey))
errs <- http.ListenAndServeTLS(p, cfg.serverCert, cfg.serverKey, api.MakeHandler(svc, logger))
return
errCh := make(chan error)
server := &http.Server{Addr: p, Handler: api.MakeHandler(svc, logger)}
switch {
case cfg.serverCert != "" || cfg.serverKey != "":
logger.Info(fmt.Sprintf("Certs service started using https on port %s with cert %s key %s", cfg.httpPort, cfg.serverCert, cfg.serverKey))
go func() {
errCh <- server.ListenAndServeTLS(cfg.serverCert, cfg.serverKey)
}()
default:
logger.Info(fmt.Sprintf("Certs service started using http on port %s", cfg.httpPort))
go func() {
errCh <- http.ListenAndServe(p, api.MakeHandler(svc, logger))
}()
}
select {
case <-ctx.Done():
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
defer cancelShutdown()
if err := server.Shutdown(ctxShutdown); err != nil {
logger.Error(fmt.Sprintf("Certs service error occurred during shutdown at %s: %s", p, err))
return fmt.Errorf("certs service error occurred during shutdown at %s: %w", p, err)
}
logger.Info(fmt.Sprintf("Certs service shutdown of http at %s", p))
return nil
case err := <-errCh:
return err
}
logger.Info(fmt.Sprintf("Certs service started using http on port %s", cfg.httpPort))
errs <- http.ListenAndServe(p, api.MakeHandler(svc, logger))
}
func loadCertificates(conf config) (tls.Certificate, *x509.Certificate, error) {

View File

@ -4,15 +4,14 @@
package main
import (
"context"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"os/signal"
"strconv"
"syscall"
"time"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
@ -20,17 +19,21 @@ import (
"github.com/mainflux/mainflux/coap"
"github.com/mainflux/mainflux/coap/api"
logger "github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
thingsapi "github.com/mainflux/mainflux/things/api/auth/grpc"
broker "github.com/nats-io/nats.go"
opentracing "github.com/opentracing/opentracing-go"
gocoap "github.com/plgd-dev/go-coap/v2"
stdprometheus "github.com/prometheus/client_golang/prometheus"
jconfig "github.com/uber/jaeger-client-go/config"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
const (
stopWaitTime = 5 * time.Second
defPort = "5683"
defNatsURL = "nats://localhost:4222"
defLogLevel = "error"
@ -63,6 +66,8 @@ type config struct {
func main() {
cfg := loadConfig()
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
logger, err := logger.New(os.Stdout, cfg.logLevel)
if err != nil {
@ -103,19 +108,25 @@ func main() {
}, []string{"method"}),
)
errs := make(chan error, 2)
g.Go(func() error {
return startHTTPServer(ctx, cfg.port, logger)
})
go startHTTPServer(cfg.port, logger, errs)
go startCOAPServer(cfg, svc, nil, logger, errs)
g.Go(func() error {
return startCOAPServer(ctx, cfg, svc, nil, logger)
})
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("CoAP adapter service shutdown by signal: %s", sig))
}
return nil
})
err = <-errs
logger.Error(fmt.Sprintf("CoAP adapter terminated: %s", err))
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("CoAP adapter service terminated: %s", err))
}
}
func loadConfig() config {
@ -189,14 +200,43 @@ func initJaeger(svcName, url string, logger logger.Logger) (opentracing.Tracer,
return tracer, closer
}
func startHTTPServer(port string, logger logger.Logger, errs chan error) {
func startHTTPServer(ctx context.Context, port string, logger logger.Logger) error {
p := fmt.Sprintf(":%s", port)
errCh := make(chan error)
server := &http.Server{Addr: p, Handler: api.MakeHTTPHandler()}
logger.Info(fmt.Sprintf("CoAP service started, exposed port %s", port))
errs <- http.ListenAndServe(p, api.MakeHTTPHandler())
go func() {
errCh <- server.ListenAndServe()
}()
select {
case <-ctx.Done():
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
defer cancelShutdown()
if err := server.Shutdown(ctxShutdown); err != nil {
logger.Error(fmt.Sprintf("CoAP adapter service error occurred during shutdown at %s: %s", p, err))
return fmt.Errorf("CoAP adapter service error occurred during shutdown at %s: %w", p, err)
}
logger.Info(fmt.Sprintf("CoAP adapter service shutdown at %s", p))
return nil
case err := <-errCh:
return err
}
}
func startCOAPServer(cfg config, svc coap.Service, auth mainflux.ThingsServiceClient, l logger.Logger, errs chan error) {
func startCOAPServer(ctx context.Context, cfg config, svc coap.Service, auth mainflux.ThingsServiceClient, l logger.Logger) error {
p := fmt.Sprintf(":%s", cfg.port)
errCh := make(chan error)
l.Info(fmt.Sprintf("CoAP adapter service started, exposed port %s", cfg.port))
errs <- gocoap.ListenAndServe("udp", p, api.MakeCoAPHandler(svc, l))
go func() {
errCh <- gocoap.ListenAndServe("udp", p, api.MakeCoAPHandler(svc, l))
}()
select {
case <-ctx.Done():
l.Info(fmt.Sprintf("CoAP adapter service shutdown of http at %s", p))
return nil
case err := <-errCh:
return err
}
}

View File

@ -4,15 +4,14 @@
package main
import (
"context"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"os/signal"
"strconv"
"syscall"
"time"
"google.golang.org/grpc/credentials"
@ -22,15 +21,19 @@ import (
adapter "github.com/mainflux/mainflux/http"
"github.com/mainflux/mainflux/http/api"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/pkg/messaging/nats"
thingsapi "github.com/mainflux/mainflux/things/api/auth/grpc"
"github.com/opentracing/opentracing-go"
stdprometheus "github.com/prometheus/client_golang/prometheus"
jconfig "github.com/uber/jaeger-client-go/config"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
)
const (
stopWaitTime = 5 * time.Second
defLogLevel = "error"
defClientTLS = "false"
defCACerts = ""
@ -63,6 +66,8 @@ type config struct {
func main() {
cfg := loadConfig()
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
logger, err := logger.New(os.Stdout, cfg.logLevel)
if err != nil {
@ -105,22 +110,21 @@ func main() {
}, []string{"method"}),
)
errs := make(chan error, 2)
g.Go(func() error {
return startHTTPServer(ctx, svc, cfg, logger, tracer)
})
g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("HTTP adapter service shutdown by signal: %s", sig))
}
return nil
})
go func() {
p := fmt.Sprintf(":%s", cfg.port)
logger.Info(fmt.Sprintf("HTTP adapter service started on port %s", cfg.port))
errs <- http.ListenAndServe(p, api.MakeHandler(svc, tracer, logger))
}()
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("HTTP adapter service terminated: %s", err))
}
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
err = <-errs
logger.Error(fmt.Sprintf("HTTP adapter terminated: %s", err))
}
func loadConfig() config {
@ -193,3 +197,27 @@ func connectToThings(cfg config, logger logger.Logger) *grpc.ClientConn {
}
return conn
}
func startHTTPServer(ctx context.Context, svc adapter.Service, cfg config, logger logger.Logger, tracer opentracing.Tracer) error {
p := fmt.Sprintf(":%s", cfg.port)
errCh := make(chan error)
server := &http.Server{Addr: p, Handler: api.MakeHandler(svc, tracer, logger)}
logger.Info(fmt.Sprintf("HTTP adapter service started on port %s", cfg.port))
go func() {
errCh <- server.ListenAndServe()
}()
select {
case <-ctx.Done():
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
defer cancelShutdown()
if err := server.Shutdown(ctxShutdown); err != nil {
logger.Error(fmt.Sprintf("HTTP adapter service error occurred during shutdown at %s: %s", p, err))
return fmt.Errorf("http adapter service error occurred during shutdown at %s: %w", p, err)
}
logger.Info(fmt.Sprintf("HTTP adapter service shutdown of http at %s", p))
return nil
case err := <-errCh:
return err
}
}

View File

@ -1,15 +1,14 @@
package main
import (
"context"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"os/signal"
"strconv"
"syscall"
"time"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
@ -17,6 +16,7 @@ import (
"github.com/mainflux/mainflux"
authapi "github.com/mainflux/mainflux/auth/api/grpc"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/readers"
"github.com/mainflux/mainflux/readers/api"
"github.com/mainflux/mainflux/readers/influxdb"
@ -24,11 +24,14 @@ import (
opentracing "github.com/opentracing/opentracing-go"
stdprometheus "github.com/prometheus/client_golang/prometheus"
jconfig "github.com/uber/jaeger-client-go/config"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
const (
stopWaitTime = 5 * time.Second
svcName = "influxdb-reader"
defLogLevel = "error"
defPort = "8180"
@ -86,6 +89,9 @@ type config struct {
func main() {
cfg, clientCfg := loadConfigs()
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
logger, err := logger.New(os.Stdout, cfg.logLevel)
if err != nil {
log.Fatalf(err.Error())
@ -115,17 +121,21 @@ func main() {
repo := newService(client, cfg.dbName, logger)
errs := make(chan error, 2)
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
g.Go(func() error {
return startHTTPServer(ctx, repo, tc, auth, cfg, logger)
})
go startHTTPServer(repo, tc, auth, cfg, logger, errs)
g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("InfluxDB reader service shutdown by signal: %s", sig))
}
return nil
})
err = <-errs
logger.Error(fmt.Sprintf("InfluxDB writer service terminated: %s", err))
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("InfluxDB reader service terminated: %s", err))
}
}
func connectToAuth(cfg config, logger logger.Logger) *grpc.ClientConn {
@ -270,14 +280,35 @@ func newService(client influxdata.Client, dbName string, logger logger.Logger) r
return repo
}
func startHTTPServer(repo readers.MessageRepository, tc mainflux.ThingsServiceClient, ac mainflux.AuthServiceClient, cfg config, logger logger.Logger, errs chan error) {
func startHTTPServer(ctx context.Context, repo readers.MessageRepository, tc mainflux.ThingsServiceClient, ac mainflux.AuthServiceClient, cfg config, logger logger.Logger) error {
p := fmt.Sprintf(":%s", cfg.port)
if cfg.serverCert != "" || cfg.serverKey != "" {
errCh := make(chan error)
server := &http.Server{Addr: p, Handler: api.MakeHandler(repo, tc, ac, "influxdb-reader", logger)}
switch {
case cfg.serverCert != "" || cfg.serverKey != "":
logger.Info(fmt.Sprintf("InfluxDB reader service started using https on port %s with cert %s key %s",
cfg.port, cfg.serverCert, cfg.serverKey))
errs <- http.ListenAndServeTLS(p, cfg.serverCert, cfg.serverKey, api.MakeHandler(repo, tc, ac, svcName, logger))
return
go func() {
errCh <- server.ListenAndServeTLS(cfg.serverCert, cfg.serverKey)
}()
default:
logger.Info(fmt.Sprintf("InfluxDB reader service started, exposed port %s", cfg.port))
go func() {
errCh <- server.ListenAndServe()
}()
}
select {
case <-ctx.Done():
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
defer cancelShutdown()
if err := server.Shutdown(ctxShutdown); err != nil {
logger.Error(fmt.Sprintf("InfluxDB reader service error occurred during shutdown at %s: %s", p, err))
return fmt.Errorf("influxDB reader service occurred during shutdown at %s: %w", p, err)
}
logger.Info(fmt.Sprintf("InfluxDB reader service shutdown of http at %s", p))
return nil
case err := <-errCh:
return err
}
logger.Info(fmt.Sprintf("InfluxDB reader service started, exposed port %s", cfg.port))
errs <- http.ListenAndServe(p, api.MakeHandler(repo, tc, ac, svcName, logger))
}

View File

@ -4,12 +4,12 @@
package main
import (
"context"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
influxdata "github.com/influxdata/influxdb/client/v2"
@ -18,12 +18,15 @@ import (
"github.com/mainflux/mainflux/consumers/writers/api"
"github.com/mainflux/mainflux/consumers/writers/influxdb"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/pkg/messaging/nats"
stdprometheus "github.com/prometheus/client_golang/prometheus"
"golang.org/x/sync/errgroup"
)
const (
svcName = "influxdb-writer"
svcName = "influxdb-writer"
stopWaitTime = 5 * time.Second
defNatsURL = "nats://localhost:4222"
defLogLevel = "error"
@ -60,6 +63,8 @@ type config struct {
func main() {
cfg, clientCfg := loadConfigs()
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
logger, err := logger.New(os.Stdout, cfg.logLevel)
if err != nil {
@ -91,17 +96,21 @@ func main() {
os.Exit(1)
}
errs := make(chan error, 2)
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
g.Go(func() error {
return startHTTPService(ctx, cfg.port, logger)
})
go startHTTPService(cfg.port, logger, errs)
g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("InfluxDB reader service shutdown by signal: %s", sig))
}
return nil
})
err = <-errs
logger.Error(fmt.Sprintf("InfluxDB writer service terminated: %s", err))
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("InfluxDB reader service terminated: %s", err))
}
}
func loadConfigs() (config, influxdata.HTTPConfig) {
@ -144,8 +153,28 @@ func makeMetrics() (*kitprometheus.Counter, *kitprometheus.Summary) {
return counter, latency
}
func startHTTPService(port string, logger logger.Logger, errs chan error) {
func startHTTPService(ctx context.Context, port string, logger logger.Logger) error {
p := fmt.Sprintf(":%s", port)
errCh := make(chan error)
server := &http.Server{Addr: p, Handler: api.MakeHandler(svcName)}
logger.Info(fmt.Sprintf("InfluxDB writer service started, exposed port %s", p))
errs <- http.ListenAndServe(p, api.MakeHandler(svcName))
go func() {
errCh <- server.ListenAndServe()
}()
select {
case <-ctx.Done():
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
defer cancelShutdown()
if err := server.Shutdown(ctxShutdown); err != nil {
logger.Error(fmt.Sprintf("InfluxDB writer service error occurred during shutdown at %s: %s", p, err))
return fmt.Errorf("influxDB writer service occurred during shutdown at %s: %w", p, err)
}
logger.Info(fmt.Sprintf("InfluxDB writer service shutdown of http at %s", p))
return nil
case err := <-errCh:
return err
}
}

View File

@ -9,9 +9,7 @@ import (
"log"
"net/http"
"os"
"os/signal"
"strconv"
"syscall"
"time"
mqttPaho "github.com/eclipse/paho.mqtt.golang"
@ -21,7 +19,9 @@ import (
"github.com/mainflux/mainflux/lora"
"github.com/mainflux/mainflux/lora/api"
"github.com/mainflux/mainflux/lora/mqtt"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/pkg/messaging/nats"
"golang.org/x/sync/errgroup"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
"github.com/mainflux/mainflux/lora/redis"
@ -29,6 +29,8 @@ import (
)
const (
stopWaitTime = 5 * time.Second
defLogLevel = "error"
defHTTPPort = "8180"
defLoraMsgURL = "tcp://localhost:1883"
@ -86,6 +88,8 @@ type config struct {
func main() {
cfg := loadConfig()
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
logger, err := logger.New(os.Stdout, cfg.logLevel)
if err != nil {
@ -132,18 +136,22 @@ func main() {
go subscribeToLoRaBroker(svc, mqttConn, cfg.loraMsgTimeout, cfg.loraMsgTopic, logger)
go subscribeToThingsES(svc, esConn, cfg.esConsumerName, logger)
errs := make(chan error, 2)
g.Go(func() error {
return startHTTPServer(ctx, cfg, logger)
})
go startHTTPServer(cfg, logger, errs)
g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("LoRa adapter shutdown by signal: %s", sig))
}
return nil
})
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("LoRa adapter terminated: %s", err))
}
err = <-errs
logger.Error(fmt.Sprintf("LoRa adapter terminated: %s", err))
}
func loadConfig() config {
@ -230,8 +238,29 @@ func newRouteMapRepository(client *r.Client, prefix string, logger logger.Logger
return redis.NewRouteMapRepository(client, prefix)
}
func startHTTPServer(cfg config, logger logger.Logger, errs chan error) {
func startHTTPServer(ctx context.Context, cfg config, logger logger.Logger) error {
p := fmt.Sprintf(":%s", cfg.httpPort)
logger.Info(fmt.Sprintf("lora-adapter service started, exposed port %s", cfg.httpPort))
errs <- http.ListenAndServe(p, api.MakeHandler())
errCh := make(chan error)
server := &http.Server{Addr: p, Handler: api.MakeHandler()}
logger.Info(fmt.Sprintf("LoRa-adapter service started, exposed port %s", cfg.httpPort))
go func() {
errCh <- http.ListenAndServe(p, api.MakeHandler())
}()
select {
case <-ctx.Done():
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
defer cancelShutdown()
if err := server.Shutdown(ctxShutdown); err != nil {
logger.Error(fmt.Sprintf("LoRa-adapter service error occurred during shutdown at %s: %s", p, err))
return fmt.Errorf("LoRa-adapter service error occurred during shutdown at %s: %w", p, err)
}
logger.Info(fmt.Sprintf("LoRa-adapter service shutdown of http at %s", p))
return nil
case err := <-errCh:
return err
}
}

View File

@ -11,15 +11,14 @@ import (
"log"
"net/http"
"os"
"os/signal"
"strconv"
"syscall"
"time"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
"github.com/mainflux/mainflux"
authapi "github.com/mainflux/mainflux/auth/api/grpc"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/readers"
"github.com/mainflux/mainflux/readers/api"
"github.com/mainflux/mainflux/readers/mongodb"
@ -29,11 +28,14 @@ import (
jconfig "github.com/uber/jaeger-client-go/config"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
const (
stopWaitTime = 5 * time.Second
svcName = "mongodb-reader"
defLogLevel = "error"
defPort = "8180"
@ -85,6 +87,8 @@ type config struct {
func main() {
cfg := loadConfigs()
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
logger, err := logger.New(os.Stdout, cfg.logLevel)
if err != nil {
log.Fatalf(err.Error())
@ -110,17 +114,22 @@ func main() {
repo := newService(db, logger)
errs := make(chan error, 2)
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
g.Go(func() error {
return startHTTPServer(ctx, repo, tc, auth, cfg, logger)
})
go startHTTPServer(repo, tc, auth, cfg, logger, errs)
g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("MongoDB reader service shutdown by signal: %s", sig))
}
return nil
})
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("MongoDB reader service terminated: %s", err))
}
err = <-errs
logger.Error(fmt.Sprintf("MongoDB reader service terminated: %s", err))
}
func connectToAuth(cfg config, logger logger.Logger) *grpc.ClientConn {
@ -265,14 +274,36 @@ func newService(db *mongo.Database, logger logger.Logger) readers.MessageReposit
return repo
}
func startHTTPServer(repo readers.MessageRepository, tc mainflux.ThingsServiceClient, ac mainflux.AuthServiceClient, cfg config, logger logger.Logger, errs chan error) {
func startHTTPServer(ctx context.Context, repo readers.MessageRepository, tc mainflux.ThingsServiceClient, ac mainflux.AuthServiceClient, cfg config, logger logger.Logger) error {
p := fmt.Sprintf(":%s", cfg.port)
if cfg.serverCert != "" || cfg.serverKey != "" {
errCh := make(chan error)
server := &http.Server{Addr: p, Handler: api.MakeHandler(repo, tc, ac, "mongodb-reader", logger)}
switch {
case cfg.serverCert != "" || cfg.serverKey != "":
logger.Info(fmt.Sprintf("Mongo reader service started using https on port %s with cert %s key %s",
cfg.port, cfg.serverCert, cfg.serverKey))
errs <- http.ListenAndServeTLS(p, cfg.serverCert, cfg.serverKey, api.MakeHandler(repo, tc, ac, svcName, logger))
return
go func() {
errCh <- server.ListenAndServeTLS(cfg.serverCert, cfg.serverKey)
}()
default:
logger.Info(fmt.Sprintf("Mongo reader service started, exposed port %s", cfg.port))
go func() {
errCh <- server.ListenAndServe()
}()
}
select {
case <-ctx.Done():
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
defer cancelShutdown()
if err := server.Shutdown(ctxShutdown); err != nil {
logger.Error(fmt.Sprintf("MongoDB reader service error occurred during shutdown at %s: %s", p, err))
return fmt.Errorf("mongodb reader service occurred during shutdown at %s: %w", p, err)
}
logger.Info(fmt.Sprintf("MongoDB reader service shutdown of http at %s", p))
return nil
case err := <-errCh:
return err
}
logger.Info(fmt.Sprintf("Mongo reader service started, exposed port %s", cfg.port))
errs <- http.ListenAndServe(p, api.MakeHandler(repo, tc, ac, svcName, logger))
}

View File

@ -9,8 +9,7 @@ import (
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
"github.com/mainflux/mainflux"
@ -18,14 +17,17 @@ import (
"github.com/mainflux/mainflux/consumers/writers/api"
"github.com/mainflux/mainflux/consumers/writers/mongodb"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/pkg/messaging/nats"
stdprometheus "github.com/prometheus/client_golang/prometheus"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"golang.org/x/sync/errgroup"
)
const (
svcName = "mongodb-writer"
svcName = "mongodb-writer"
stopWaitTime = 5 * time.Second
defLogLevel = "error"
defNatsURL = "nats://localhost:4222"
@ -56,6 +58,8 @@ type config struct {
func main() {
cfg := loadConfigs()
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
logger, err := logger.New(os.Stdout, cfg.logLevel)
if err != nil {
@ -88,17 +92,22 @@ func main() {
os.Exit(1)
}
errs := make(chan error, 2)
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
g.Go(func() error {
return startHTTPService(ctx, cfg.port, logger)
})
go startHTTPService(cfg.port, logger, errs)
g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("MongoDB reader service shutdown by signal: %s", sig))
}
return nil
})
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("MongoDB writer service terminated: %s", err))
}
err = <-errs
logger.Error(fmt.Sprintf("MongoDB writer service terminated: %s", err))
}
func loadConfigs() config {
@ -131,8 +140,29 @@ func makeMetrics() (*kitprometheus.Counter, *kitprometheus.Summary) {
return counter, latency
}
func startHTTPService(port string, logger logger.Logger, errs chan error) {
func startHTTPService(ctx context.Context, port string, logger logger.Logger) error {
p := fmt.Sprintf(":%s", port)
logger.Info(fmt.Sprintf("Mongodb writer service started, exposed port %s", p))
errs <- http.ListenAndServe(p, api.MakeHandler(svcName))
errCh := make(chan error)
server := &http.Server{Addr: p, Handler: api.MakeHandler(svcName)}
logger.Info(fmt.Sprintf("MongoDB writer service started, exposed port %s", p))
go func() {
errCh <- server.ListenAndServe()
}()
select {
case <-ctx.Done():
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
defer cancelShutdown()
if err := server.Shutdown(ctxShutdown); err != nil {
logger.Error(fmt.Sprintf("MongoDB writer service error occurred during shutdown at %s: %s", p, err))
return fmt.Errorf("mongodb writer service occurred during shutdown at %s: %w", p, err)
}
logger.Info(fmt.Sprintf("MongoDB writer service shutdown of http at %s", p))
return nil
case err := <-errCh:
return err
}
}

View File

@ -1,15 +1,14 @@
package main
import (
"context"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"os/signal"
"strconv"
"syscall"
"time"
"github.com/cenkalti/backoff/v4"
@ -29,6 +28,7 @@ import (
ws "github.com/mainflux/mproxy/pkg/websocket"
opentracing "github.com/opentracing/opentracing-go"
jconfig "github.com/uber/jaeger-client-go/config"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
@ -121,6 +121,8 @@ type config struct {
func main() {
cfg := loadConfig()
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
logger, err := mflog.New(os.Stdout, cfg.logLevel)
if err != nil {
@ -185,22 +187,27 @@ func main() {
// Event handler for MQTT hooks
h := mqtt.NewHandler([]messaging.Publisher{np}, es, logger, authClient)
errs := make(chan error, 2)
logger.Info(fmt.Sprintf("Starting MQTT proxy on port %s", cfg.mqttPort))
go proxyMQTT(cfg, logger, h, errs)
g.Go(func() error {
return proxyMQTT(ctx, cfg, logger, h)
})
logger.Info(fmt.Sprintf("Starting MQTT over WS proxy on port %s", cfg.httpPort))
go proxyWS(cfg, logger, h, errs)
g.Go(func() error {
return proxyWS(ctx, cfg, logger, h)
})
go func() {
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("mProxy shutdown by signal: %s", sig))
}
return nil
})
err = <-errs
logger.Error(fmt.Sprintf("mProxy terminated: %s", err))
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("mProxy terminated: %s", err))
}
}
func loadConfig() config {
@ -309,19 +316,43 @@ func connectToRedis(redisURL, redisPass, redisDB string, logger mflog.Logger) *r
})
}
func proxyMQTT(cfg config, logger mflog.Logger, handler session.Handler, errs chan error) {
func proxyMQTT(ctx context.Context, cfg config, logger mflog.Logger, handler session.Handler) error {
address := fmt.Sprintf(":%s", cfg.mqttPort)
target := fmt.Sprintf("%s:%s", cfg.mqttTargetHost, cfg.mqttTargetPort)
mp := mp.New(address, target, handler, logger)
errs <- mp.Listen()
errCh := make(chan error)
go func() {
errCh <- mp.Listen()
}()
select {
case <-ctx.Done():
logger.Info(fmt.Sprintf("proxy MQTT shutdown at %s", target))
return nil
case err := <-errCh:
return err
}
}
func proxyWS(cfg config, logger mflog.Logger, handler session.Handler, errs chan error) {
func proxyWS(ctx context.Context, cfg config, logger mflog.Logger, handler session.Handler) error {
target := fmt.Sprintf("%s:%s", cfg.httpTargetHost, cfg.httpTargetPort)
wp := ws.New(target, cfg.httpTargetPath, "ws", handler, logger)
http.Handle("/mqtt", wp.Handler())
errs <- wp.Listen(cfg.httpPort)
errCh := make(chan error)
go func() {
errCh <- wp.Listen(cfg.httpPort)
}()
select {
case <-ctx.Done():
logger.Info(fmt.Sprintf("proxy MQTT WS shutdown at %s", target))
return nil
case err := <-errCh:
return err
}
}
func healthcheck(cfg config) func() error {

View File

@ -9,9 +9,8 @@ import (
"log"
"net/http"
"os"
"os/signal"
"strconv"
"syscall"
"time"
r "github.com/go-redis/redis/v8"
"github.com/mainflux/mainflux"
@ -21,13 +20,17 @@ import (
"github.com/mainflux/mainflux/opcua/db"
"github.com/mainflux/mainflux/opcua/gopcua"
"github.com/mainflux/mainflux/opcua/redis"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/pkg/messaging/nats"
"golang.org/x/sync/errgroup"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
stdprometheus "github.com/prometheus/client_golang/prometheus"
)
const (
stopWaitTime = 5 * time.Second
defLogLevel = "error"
defHTTPPort = "8180"
defOPCIntervalMs = "1000"
@ -81,6 +84,8 @@ type config struct {
func main() {
cfg := loadConfig()
httpCtx, httpCancel := context.WithCancel(context.Background())
g, httpCtx := errgroup.WithContext(httpCtx)
logger, err := logger.New(os.Stdout, cfg.logLevel)
if err != nil {
@ -129,18 +134,21 @@ func main() {
go subscribeToStoredSubs(sub, cfg.opcuaConfig, logger)
go subscribeToThingsES(svc, esConn, cfg.esConsumerName, logger)
errs := make(chan error, 2)
g.Go(func() error {
return startHTTPServer(httpCtx, svc, cfg, logger)
})
go startHTTPServer(svc, cfg, logger, errs)
g.Go(func() error {
if sig := errors.SignalHandler(httpCtx); sig != nil {
httpCancel()
logger.Info(fmt.Sprintf("OPC-UA adapter service shutdown by signal: %s", sig))
}
return nil
})
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
err = <-errs
logger.Error(fmt.Sprintf("OPC-UA adapter terminated: %s", err))
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("OPC-UA adapter service terminated: %s", err))
}
}
func loadConfig() config {
@ -216,8 +224,28 @@ func newRouteMapRepositoy(client *r.Client, prefix string, logger logger.Logger)
return redis.NewRouteMapRepository(client, prefix)
}
func startHTTPServer(svc opcua.Service, cfg config, logger logger.Logger, errs chan error) {
func startHTTPServer(ctx context.Context, svc opcua.Service, cfg config, logger logger.Logger) error {
p := fmt.Sprintf(":%s", cfg.httpPort)
logger.Info(fmt.Sprintf("opcua-adapter service started, exposed port %s", cfg.httpPort))
errs <- http.ListenAndServe(p, api.MakeHandler(svc, logger))
errCh := make(chan error)
server := &http.Server{Addr: p, Handler: api.MakeHandler(svc, logger)}
logger.Info(fmt.Sprintf("OPC-UA adapter service started, exposed port %s", cfg.httpPort))
go func() {
errCh <- server.ListenAndServe()
}()
select {
case <-ctx.Done():
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
defer cancelShutdown()
if err := server.Shutdown(ctxShutdown); err != nil {
logger.Error(fmt.Sprintf("OPC-UA adapter service error occurred during shutdown at %s: %s", p, err))
return fmt.Errorf("OPC-UA adapter service error occurred during shutdown at %s: %w", p, err)
}
logger.Info(fmt.Sprintf("OPC-UA adapter service shutdown of http at %s", p))
return nil
case err := <-errCh:
return err
}
}

View File

@ -4,15 +4,14 @@
package main
import (
"context"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"os/signal"
"strconv"
"syscall"
"time"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
@ -20,6 +19,7 @@ import (
"github.com/mainflux/mainflux"
authapi "github.com/mainflux/mainflux/auth/api/grpc"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/readers"
"github.com/mainflux/mainflux/readers/api"
"github.com/mainflux/mainflux/readers/postgres"
@ -27,13 +27,15 @@ import (
opentracing "github.com/opentracing/opentracing-go"
stdprometheus "github.com/prometheus/client_golang/prometheus"
jconfig "github.com/uber/jaeger-client-go/config"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
const (
svcName = "postgres-reader"
sep = ","
svcName = "postgres-reader"
sep = ","
stopWaitTime = 5 * time.Second
defLogLevel = "error"
defPort = "8180"
@ -89,6 +91,8 @@ type config struct {
func main() {
cfg := loadConfig()
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
logger, err := logger.New(os.Stdout, cfg.logLevel)
if err != nil {
@ -116,18 +120,21 @@ func main() {
repo := newService(db, logger)
errs := make(chan error, 2)
g.Go(func() error {
return startHTTPServer(ctx, repo, tc, auth, cfg.port, logger)
})
go startHTTPServer(repo, tc, auth, cfg.port, logger, errs)
g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("Postgres reader service shutdown by signal: %s", sig))
}
return nil
})
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
err = <-errs
logger.Error(fmt.Sprintf("Postgres reader service terminated: %s", err))
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("Postgres reader service terminated: %s", err))
}
}
func connectToAuth(cfg config, logger logger.Logger) *grpc.ClientConn {
@ -278,8 +285,27 @@ func newService(db *sqlx.DB, logger logger.Logger) readers.MessageRepository {
return svc
}
func startHTTPServer(repo readers.MessageRepository, tc mainflux.ThingsServiceClient, ac mainflux.AuthServiceClient, port string, logger logger.Logger, errs chan error) {
func startHTTPServer(ctx context.Context, repo readers.MessageRepository, tc mainflux.ThingsServiceClient, ac mainflux.AuthServiceClient, port string, logger logger.Logger) error {
p := fmt.Sprintf(":%s", port)
errCh := make(chan error)
server := &http.Server{Addr: p, Handler: api.MakeHandler(repo, tc, ac, svcName, logger)}
logger.Info(fmt.Sprintf("Postgres reader service started, exposed port %s", port))
errs <- http.ListenAndServe(p, api.MakeHandler(repo, tc, ac, svcName, logger))
go func() {
errCh <- server.ListenAndServe()
}()
select {
case <-ctx.Done():
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
defer cancelShutdown()
if err := server.Shutdown(ctxShutdown); err != nil {
logger.Error(fmt.Sprintf("Postgres reader service error occurred during shutdown at %s: %s", p, err))
return fmt.Errorf("postgres reader service occurred during shutdown at %s: %w", p, err)
}
logger.Info(fmt.Sprintf("Postgres reader service shutdown of http at %s", p))
return nil
case err := <-errCh:
return err
}
}

View File

@ -4,12 +4,12 @@
package main
import (
"context"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
"github.com/jmoiron/sqlx"
@ -18,13 +18,16 @@ import (
"github.com/mainflux/mainflux/consumers/writers/api"
"github.com/mainflux/mainflux/consumers/writers/postgres"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/pkg/messaging/nats"
stdprometheus "github.com/prometheus/client_golang/prometheus"
"golang.org/x/sync/errgroup"
)
const (
svcName = "postgres-writer"
sep = ","
svcName = "postgres-writer"
sep = ","
stopWaitTime = 5 * time.Second
defLogLevel = "error"
defNatsURL = "nats://localhost:4222"
@ -65,6 +68,8 @@ type config struct {
func main() {
cfg := loadConfig()
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
logger, err := logger.New(os.Stdout, cfg.logLevel)
if err != nil {
@ -87,18 +92,22 @@ func main() {
logger.Error(fmt.Sprintf("Failed to create Postgres writer: %s", err))
}
errs := make(chan error, 2)
g.Go(func() error {
return startHTTPServer(ctx, cfg.port, logger)
})
go startHTTPServer(cfg.port, errs, logger)
g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("Postgres writer service shutdown by signal: %s", sig))
}
return nil
})
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("Postgres writer service terminated: %s", err))
}
err = <-errs
logger.Error(fmt.Sprintf("Postgres writer service terminated: %s", err))
}
func loadConfig() config {
@ -154,8 +163,27 @@ func newService(db *sqlx.DB, logger logger.Logger) consumers.Consumer {
return svc
}
func startHTTPServer(port string, errs chan error, logger logger.Logger) {
func startHTTPServer(ctx context.Context, port string, logger logger.Logger) error {
p := fmt.Sprintf(":%s", port)
errCh := make(chan error)
server := &http.Server{Addr: p, Handler: api.MakeHandler(svcName)}
logger.Info(fmt.Sprintf("Postgres writer service started, exposed port %s", port))
errs <- http.ListenAndServe(p, api.MakeHandler(svcName))
go func() {
errCh <- server.ListenAndServe()
}()
select {
case <-ctx.Done():
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
defer cancelShutdown()
if err := server.Shutdown(ctxShutdown); err != nil {
logger.Error(fmt.Sprintf("Postgres writer service error occurred during shutdown at %s: %s", p, err))
return fmt.Errorf("postgres writer service occurred during shutdown at %s: %w", p, err)
}
logger.Info(fmt.Sprintf("Postgres writer service shutdown of http at %s", p))
return nil
case err := <-errCh:
return err
}
}

View File

@ -1,15 +1,15 @@
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"reflect"
"strconv"
"syscall"
"time"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/logger"
@ -18,10 +18,13 @@ import (
"github.com/mainflux/mainflux/provision"
"github.com/mainflux/mainflux/provision/api"
"github.com/mainflux/mainflux/things"
"golang.org/x/sync/errgroup"
)
const (
defLogLevel = "debug"
stopWaitTime = 5 * time.Second
defLogLevel = "error"
defConfigFile = "config.toml"
defTLS = "false"
defServerCert = ""
@ -79,6 +82,9 @@ var (
func main() {
cfg, err := loadConfig()
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
if err != nil {
log.Fatalf(err.Error())
}
@ -107,30 +113,56 @@ func main() {
svc := provision.New(cfg, SDK, logger)
svc = api.NewLoggingMiddleware(svc, logger)
errs := make(chan error, 2)
g.Go(func() error {
return startHTTPServer(ctx, svc, cfg, logger)
})
go startHTTPServer(svc, cfg, logger, errs)
g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("Provision service shutdown by signal: %s", sig))
}
return nil
})
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("Provision service terminated: %s", err))
}
err = <-errs
logger.Error(fmt.Sprintf("Provision service terminated: %s", err))
}
func startHTTPServer(svc provision.Service, cfg provision.Config, logger logger.Logger, errs chan error) {
func startHTTPServer(ctx context.Context, svc provision.Service, cfg provision.Config, logger logger.Logger) error {
p := fmt.Sprintf(":%s", cfg.Server.HTTPPort)
if cfg.Server.ServerCert != "" || cfg.Server.ServerKey != "" {
errCh := make(chan error)
server := &http.Server{Addr: p, Handler: api.MakeHandler(svc, logger)}
switch {
case cfg.Server.ServerCert != "" || cfg.Server.ServerKey != "":
logger.Info(fmt.Sprintf("Provision service started using https on port %s with cert %s key %s",
cfg.Server.HTTPPort, cfg.Server.ServerCert, cfg.Server.ServerKey))
errs <- http.ListenAndServeTLS(p, cfg.Server.ServerCert, cfg.Server.ServerKey, api.MakeHandler(svc, logger))
return
go func() {
errCh <- server.ListenAndServeTLS(cfg.Server.ServerCert, cfg.Server.ServerKey)
}()
default:
logger.Info(fmt.Sprintf("Provision service started using http on port %s", cfg.Server.HTTPPort))
go func() {
errCh <- server.ListenAndServe()
}()
}
select {
case <-ctx.Done():
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
defer cancelShutdown()
if err := server.Shutdown(ctxShutdown); err != nil {
logger.Error(fmt.Sprintf("Provision service error occurred during shutdown at %s: %s", p, err))
return fmt.Errorf("provision service occurred during shutdown at %s: %w", p, err)
}
logger.Info(fmt.Sprintf("Provision service shutdown of http at %s", p))
return nil
case err := <-errCh:
return err
}
logger.Info(fmt.Sprintf("Provision service started using http on port %s", cfg.Server.HTTPPort))
errs <- http.ListenAndServe(p, api.MakeHandler(svc, logger))
}
func loadConfigFromFile(file string) (provision.Config, error) {

View File

@ -4,15 +4,14 @@
package main
import (
"context"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"os/signal"
"strconv"
"syscall"
"time"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
@ -23,10 +22,12 @@ import (
"github.com/mainflux/mainflux/consumers/notifiers"
"github.com/mainflux/mainflux/consumers/notifiers/api"
"github.com/mainflux/mainflux/consumers/notifiers/postgres"
"golang.org/x/sync/errgroup"
mfsmpp "github.com/mainflux/mainflux/consumers/notifiers/smpp"
"github.com/mainflux/mainflux/consumers/notifiers/tracing"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/pkg/messaging/nats"
"github.com/mainflux/mainflux/pkg/ulid"
opentracing "github.com/opentracing/opentracing-go"
@ -37,6 +38,8 @@ import (
)
const (
stopWaitTime = 5 * time.Second
defLogLevel = "error"
defDBHost = "localhost"
defDBPort = "5432"
@ -121,6 +124,8 @@ type config struct {
func main() {
cfg := loadConfig()
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
logger, err := logger.New(os.Stdout, cfg.logLevel)
if err != nil {
@ -152,22 +157,27 @@ func main() {
defer dbCloser.Close()
svc := newService(db, dbTracer, auth, cfg, logger)
errs := make(chan error, 2)
if err = consumers.Start(pubSub, svc, cfg.configPath, logger); err != nil {
logger.Error(fmt.Sprintf("Failed to create Postgres writer: %s", err))
}
go startHTTPServer(tracer, svc, cfg.httpPort, cfg.serverCert, cfg.serverKey, logger, errs)
g.Go(func() error {
return startHTTPServer(ctx, tracer, svc, cfg.httpPort, cfg.serverCert, cfg.serverKey, logger)
})
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("SMPP notifier service shutdown by signal: %s", sig))
}
return nil
})
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("SMPP notifier service terminated: %s", err))
}
err = <-errs
logger.Error(fmt.Sprintf("Users service terminated: %s", err))
}
func loadConfig() config {
@ -323,13 +333,36 @@ func newService(db *sqlx.DB, tracer opentracing.Tracer, auth mainflux.AuthServic
return svc
}
func startHTTPServer(tracer opentracing.Tracer, svc notifiers.Service, port string, certFile string, keyFile string, logger logger.Logger, errs chan error) {
func startHTTPServer(ctx context.Context, tracer opentracing.Tracer, svc notifiers.Service, port string, certFile string, keyFile string, logger logger.Logger) error {
p := fmt.Sprintf(":%s", port)
if certFile != "" || keyFile != "" {
errCh := make(chan error)
server := &http.Server{Addr: p, Handler: api.MakeHandler(svc, tracer, logger)}
switch {
case certFile != "" || keyFile != "":
logger.Info(fmt.Sprintf("SMPP notifier service started using https, cert %s key %s, exposed port %s", certFile, keyFile, port))
errs <- http.ListenAndServeTLS(p, certFile, keyFile, api.MakeHandler(svc, tracer, logger))
} else {
go func() {
errCh <- server.ListenAndServeTLS(certFile, keyFile)
}()
default:
logger.Info(fmt.Sprintf("SMPP notifier service started using http, exposed port %s", port))
errs <- http.ListenAndServe(p, api.MakeHandler(svc, tracer, logger))
go func() {
errCh <- server.ListenAndServe()
}()
}
select {
case <-ctx.Done():
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
defer cancelShutdown()
if err := server.Shutdown(ctxShutdown); err != nil {
logger.Error(fmt.Sprintf("SMPP notifier service error occurred during shutdown at %s: %s", p, err))
return fmt.Errorf("smpp notifier service occurred during shutdown at %s: %w", p, err)
}
logger.Info(fmt.Sprintf("SMPP notifier service shutdown of http at %s", p))
return nil
case err := <-errCh:
return err
}
}

View File

@ -4,15 +4,14 @@
package main
import (
"context"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"os/signal"
"strconv"
"syscall"
"time"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
@ -27,16 +26,20 @@ import (
"github.com/mainflux/mainflux/consumers/notifiers/tracing"
"github.com/mainflux/mainflux/internal/email"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/pkg/messaging/nats"
"github.com/mainflux/mainflux/pkg/ulid"
opentracing "github.com/opentracing/opentracing-go"
stdprometheus "github.com/prometheus/client_golang/prometheus"
jconfig "github.com/uber/jaeger-client-go/config"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
const (
stopWaitTime = 5 * time.Second
defLogLevel = "error"
defDBHost = "localhost"
defDBPort = "5432"
@ -119,6 +122,8 @@ type config struct {
func main() {
cfg := loadConfig()
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
logger, err := logger.New(os.Stdout, cfg.logLevel)
if err != nil {
@ -150,22 +155,27 @@ func main() {
defer dbCloser.Close()
svc := newService(db, dbTracer, auth, cfg, logger)
errs := make(chan error, 2)
if err = consumers.Start(pubSub, svc, cfg.configPath, logger); err != nil {
logger.Error(fmt.Sprintf("Failed to create Postgres writer: %s", err))
}
go startHTTPServer(tracer, svc, cfg.httpPort, cfg.serverCert, cfg.serverKey, logger, errs)
g.Go(func() error {
return startHTTPServer(ctx, tracer, svc, cfg.httpPort, cfg.serverCert, cfg.serverKey, logger)
})
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("SMTP notifier service shutdown by signal: %s", sig))
}
return nil
})
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("SMTP notifier service terminated: %s", err))
}
err = <-errs
logger.Error(fmt.Sprintf("Users service terminated: %s", err))
}
func loadConfig() config {
@ -310,13 +320,35 @@ func newService(db *sqlx.DB, tracer opentracing.Tracer, auth mainflux.AuthServic
return svc
}
func startHTTPServer(tracer opentracing.Tracer, svc notifiers.Service, port string, certFile string, keyFile string, logger logger.Logger, errs chan error) {
func startHTTPServer(ctx context.Context, tracer opentracing.Tracer, svc notifiers.Service, port string, certFile string, keyFile string, logger logger.Logger) error {
p := fmt.Sprintf(":%s", port)
if certFile != "" || keyFile != "" {
errCh := make(chan error)
server := &http.Server{Addr: p, Handler: api.MakeHandler(svc, tracer, logger)}
switch {
case certFile != "" || keyFile != "":
logger.Info(fmt.Sprintf("SMTP notifier service started using https, cert %s key %s, exposed port %s", certFile, keyFile, port))
errs <- http.ListenAndServeTLS(p, certFile, keyFile, api.MakeHandler(svc, tracer, logger))
} else {
go func() {
errCh <- server.ListenAndServeTLS(certFile, keyFile)
}()
default:
logger.Info(fmt.Sprintf("SMTP notifier service started using http, exposed port %s", port))
errs <- http.ListenAndServe(p, api.MakeHandler(svc, tracer, logger))
go func() {
errCh <- server.ListenAndServe()
}()
}
select {
case <-ctx.Done():
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
defer cancelShutdown()
if err := server.Shutdown(ctxShutdown); err != nil {
logger.Error(fmt.Sprintf("SMTP notifier service error occurred during shutdown at %s: %s", p, err))
return fmt.Errorf("smtp notifier service occurred during shutdown at %s: %w", p, err)
}
logger.Info(fmt.Sprintf("SMTP notifier service shutdown of http at %s", p))
return nil
case err := <-errCh:
return err
}
}

View File

@ -4,6 +4,7 @@
package main
import (
"context"
"fmt"
"io"
"io/ioutil"
@ -11,9 +12,7 @@ import (
"net"
"net/http"
"os"
"os/signal"
"strconv"
"syscall"
"time"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
@ -22,6 +21,7 @@ import (
"github.com/mainflux/mainflux"
authapi "github.com/mainflux/mainflux/auth/api/grpc"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/pkg/uuid"
"github.com/mainflux/mainflux/things"
"github.com/mainflux/mainflux/things/api"
@ -35,11 +35,14 @@ import (
opentracing "github.com/opentracing/opentracing-go"
stdprometheus "github.com/prometheus/client_golang/prometheus"
jconfig "github.com/uber/jaeger-client-go/config"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
const (
stopWaitTime = 5 * time.Second
defLogLevel = "error"
defDBHost = "localhost"
defDBPort = "5432"
@ -124,6 +127,8 @@ type config struct {
func main() {
cfg := loadConfig()
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
logger, err := logger.New(os.Stdout, cfg.logLevel)
if err != nil {
@ -155,20 +160,30 @@ func main() {
defer cacheCloser.Close()
svc := newService(auth, dbTracer, cacheTracer, db, cacheClient, esClient, logger)
errs := make(chan error, 2)
go startHTTPServer(thhttpapi.MakeHandler(thingsTracer, svc, logger), cfg.httpPort, cfg, logger, errs)
go startHTTPServer(authhttpapi.MakeHandler(thingsTracer, svc, logger), cfg.authHTTPPort, cfg, logger, errs)
go startGRPCServer(svc, thingsTracer, cfg, logger, errs)
g.Go(func() error {
return startHTTPServer(ctx, "thing-http", thhttpapi.MakeHandler(thingsTracer, svc, logger), cfg.httpPort, cfg, logger)
})
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
g.Go(func() error {
return startHTTPServer(ctx, "auth-http", authhttpapi.MakeHandler(thingsTracer, svc, logger), cfg.authHTTPPort, cfg, logger)
})
err = <-errs
logger.Error(fmt.Sprintf("Things service terminated: %s", err))
g.Go(func() error {
return startGRPCServer(ctx, svc, thingsTracer, cfg, logger)
})
g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("Things service shutdown by signal: %s", sig))
}
return nil
})
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("Things service terminated: %s", err))
}
}
func loadConfig() config {
@ -336,41 +351,84 @@ func newService(auth mainflux.AuthServiceClient, dbTracer opentracing.Tracer, ca
return svc
}
func startHTTPServer(handler http.Handler, port string, cfg config, logger logger.Logger, errs chan error) {
func startHTTPServer(ctx context.Context, typ string, handler http.Handler, port string, cfg config, logger logger.Logger) error {
p := fmt.Sprintf(":%s", port)
if cfg.serverCert != "" || cfg.serverKey != "" {
logger.Info(fmt.Sprintf("Things service started using https on port %s with cert %s key %s",
port, cfg.serverCert, cfg.serverKey))
errs <- http.ListenAndServeTLS(p, cfg.serverCert, cfg.serverKey, handler)
return
errCh := make(chan error)
server := &http.Server{Addr: p, Handler: handler}
switch {
case cfg.serverCert != "" || cfg.serverKey != "":
logger.Info(fmt.Sprintf("Things %s service started using https on port %s with cert %s key %s",
typ, port, cfg.serverCert, cfg.serverKey))
go func() {
errCh <- server.ListenAndServeTLS(cfg.serverCert, cfg.serverKey)
}()
default:
logger.Info(fmt.Sprintf("Things %s service started using http on port %s", typ, cfg.httpPort))
go func() {
errCh <- server.ListenAndServe()
}()
}
logger.Info(fmt.Sprintf("Things service started using http on port %s", cfg.httpPort))
errs <- http.ListenAndServe(p, handler)
select {
case <-ctx.Done():
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
defer cancelShutdown()
if err := server.Shutdown(ctxShutdown); err != nil {
logger.Error(fmt.Sprintf("Things %s service error occurred during shutdown at %s: %s", typ, p, err))
return fmt.Errorf("things %s service occurred during shutdown at %s: %w", typ, p, err)
}
logger.Info(fmt.Sprintf("Things %s service shutdown of http at %s", typ, p))
return nil
case err := <-errCh:
return err
}
}
func startGRPCServer(svc things.Service, tracer opentracing.Tracer, cfg config, logger logger.Logger, errs chan error) {
func startGRPCServer(ctx context.Context, svc things.Service, tracer opentracing.Tracer, cfg config, logger logger.Logger) error {
p := fmt.Sprintf(":%s", cfg.authGRPCPort)
errCh := make(chan error)
var server *grpc.Server
listener, err := net.Listen("tcp", p)
if err != nil {
logger.Error(fmt.Sprintf("Failed to listen on port %s: %s", cfg.authGRPCPort, err))
os.Exit(1)
return fmt.Errorf("failed to listen on port %s: %w", cfg.authGRPCPort, err)
}
var server *grpc.Server
if cfg.serverCert != "" || cfg.serverKey != "" {
switch {
case cfg.serverCert != "" || cfg.serverKey != "":
creds, err := credentials.NewServerTLSFromFile(cfg.serverCert, cfg.serverKey)
if err != nil {
logger.Error(fmt.Sprintf("Failed to load things certificates: %s", err))
os.Exit(1)
return fmt.Errorf("failed to load things certificates: %w", err)
}
logger.Info(fmt.Sprintf("Things gRPC service started using https on port %s with cert %s key %s",
cfg.authGRPCPort, cfg.serverCert, cfg.serverKey))
server = grpc.NewServer(grpc.Creds(creds))
} else {
default:
logger.Info(fmt.Sprintf("Things gRPC service started using http on port %s", cfg.authGRPCPort))
server = grpc.NewServer()
}
mainflux.RegisterThingsServiceServer(server, authgrpcapi.NewServer(tracer, svc))
errs <- server.Serve(listener)
go func() {
errCh <- server.Serve(listener)
}()
select {
case <-ctx.Done():
c := make(chan bool)
go func() {
defer close(c)
server.GracefulStop()
}()
select {
case <-c:
case <-time.After(stopWaitTime):
}
logger.Info(fmt.Sprintf("Things gRPC service shutdown at %s", p))
return nil
case err := <-errCh:
return err
}
}

View File

@ -4,15 +4,14 @@
package main
import (
"context"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"os/signal"
"strconv"
"syscall"
"time"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
@ -20,6 +19,7 @@ import (
"github.com/mainflux/mainflux"
authapi "github.com/mainflux/mainflux/auth/api/grpc"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/readers"
"github.com/mainflux/mainflux/readers/api"
"github.com/mainflux/mainflux/readers/timescale"
@ -27,12 +27,14 @@ import (
opentracing "github.com/opentracing/opentracing-go"
stdprometheus "github.com/prometheus/client_golang/prometheus"
jconfig "github.com/uber/jaeger-client-go/config"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
const (
svcName = "timescaledb-reader"
svcName = "timescaledb-reader"
stopWaitTime = 5 * time.Second
defLogLevel = "error"
defPort = "8911"
@ -84,6 +86,8 @@ type config struct {
func main() {
cfg := loadConfig()
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
logger, err := logger.New(os.Stdout, cfg.logLevel)
if err != nil {
@ -110,18 +114,21 @@ func main() {
repo := newService(db, logger)
errs := make(chan error, 2)
g.Go(func() error {
return startHTTPServer(ctx, repo, tc, auth, cfg.port, logger)
})
go startHTTPServer(repo, tc, auth, cfg.port, logger, errs)
g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("Timescale reader service shutdown by signal: %s", sig))
}
return nil
})
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
err = <-errs
logger.Error(fmt.Sprintf("Timescale reader service terminated: %s", err))
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("Timescale reader service terminated: %s", err))
}
}
func loadConfig() config {
@ -264,8 +271,27 @@ func newService(db *sqlx.DB, logger logger.Logger) readers.MessageRepository {
return svc
}
func startHTTPServer(repo readers.MessageRepository, tc mainflux.ThingsServiceClient, ac mainflux.AuthServiceClient, port string, logger logger.Logger, errs chan error) {
func startHTTPServer(ctx context.Context, repo readers.MessageRepository, tc mainflux.ThingsServiceClient, ac mainflux.AuthServiceClient, port string, logger logger.Logger) error {
p := fmt.Sprintf(":%s", port)
errCh := make(chan error)
server := &http.Server{Addr: p, Handler: api.MakeHandler(repo, tc, ac, svcName, logger)}
logger.Info(fmt.Sprintf("Timescale reader service started, exposed port %s", port))
errs <- http.ListenAndServe(p, api.MakeHandler(repo, tc, ac, svcName, logger))
go func() {
errCh <- server.ListenAndServe()
}()
select {
case <-ctx.Done():
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
defer cancelShutdown()
if err := server.Shutdown(ctxShutdown); err != nil {
logger.Error(fmt.Sprintf("Timescale reader service error occurred during shutdown at %s: %s", p, err))
return fmt.Errorf("Timescale reader service occurred during shutdown at %s: %w", p, err)
}
logger.Info(fmt.Sprintf("Timescale reader service shutdown of http at %s", p))
return nil
case err := <-errCh:
return err
}
}

View File

@ -4,13 +4,12 @@
package main
import (
"context"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
"github.com/jmoiron/sqlx"
@ -19,12 +18,15 @@ import (
"github.com/mainflux/mainflux/consumers/writers/api"
"github.com/mainflux/mainflux/consumers/writers/timescale"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/pkg/messaging/nats"
stdprometheus "github.com/prometheus/client_golang/prometheus"
"golang.org/x/sync/errgroup"
)
const (
svcName = "timescaledb-writer"
svcName = "timescaledb-writer"
stopWaitTime = 5 * time.Second
defLogLevel = "error"
defNatsURL = "nats://localhost:4222"
@ -65,6 +67,8 @@ type config struct {
func main() {
cfg := loadConfig()
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
logger, err := logger.New(os.Stdout, cfg.logLevel)
if err != nil {
@ -87,18 +91,21 @@ func main() {
logger.Error(fmt.Sprintf("Failed to create Timescale writer: %s", err))
}
errs := make(chan error, 2)
g.Go(func() error {
return startHTTPServer(ctx, cfg.port, logger)
})
go startHTTPServer(cfg.port, errs, logger)
g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("Timescale writer service shutdown by signal: %s", sig))
}
return nil
})
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
err = <-errs
logger.Error(fmt.Sprintf("Timescale writer service terminated: %s", err))
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("Timescale writer service terminated: %s", err))
}
}
func loadConfig() config {
@ -154,8 +161,28 @@ func newService(db *sqlx.DB, logger logger.Logger) consumers.Consumer {
return svc
}
func startHTTPServer(port string, errs chan error, logger logger.Logger) {
func startHTTPServer(ctx context.Context, port string, logger logger.Logger) error {
p := fmt.Sprintf(":%s", port)
errCh := make(chan error)
server := &http.Server{Addr: p, Handler: api.MakeHandler(svcName)}
logger.Info(fmt.Sprintf("Timescale writer service started, exposed port %s", port))
errs <- http.ListenAndServe(p, api.MakeHandler(svcName))
go func() {
errCh <- server.ListenAndServe()
}()
select {
case <-ctx.Done():
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
defer cancelShutdown()
if err := server.Shutdown(ctxShutdown); err != nil {
logger.Error(fmt.Sprintf("timescale writer service error occurred during shutdown at %s: %s", p, err))
return fmt.Errorf("timescale writer service occurred during shutdown at %s: %w", p, err)
}
logger.Info(fmt.Sprintf("Timescale writer service shutdown of http at %s", p))
return nil
case err := <-errCh:
return err
}
}

View File

@ -4,15 +4,14 @@
package main
import (
"context"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"os/signal"
"strconv"
"syscall"
"time"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
@ -20,6 +19,7 @@ import (
"github.com/mainflux/mainflux"
authapi "github.com/mainflux/mainflux/auth/api/grpc"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/pkg/messaging"
"github.com/mainflux/mainflux/pkg/messaging/nats"
"github.com/mainflux/mainflux/pkg/uuid"
@ -34,12 +34,14 @@ import (
stdprometheus "github.com/prometheus/client_golang/prometheus"
jconfig "github.com/uber/jaeger-client-go/config"
"go.mongodb.org/mongo-driver/mongo"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
const (
queue = "twins"
queue = "twins"
stopWaitTime = 5 * time.Second
defLogLevel = "error"
defHTTPPort = "8180"
@ -105,6 +107,8 @@ type config struct {
func main() {
cfg := loadConfig()
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
logger, err := logger.New(os.Stdout, cfg.logLevel)
if err != nil {
@ -138,17 +142,22 @@ func main() {
tracer, closer := initJaeger("twins", cfg.jaegerURL, logger)
defer closer.Close()
errs := make(chan error, 2)
go startHTTPServer(twapi.MakeHandler(tracer, svc, logger), cfg.httpPort, cfg, logger, errs)
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
g.Go(func() error {
return startHTTPServer(ctx, twapi.MakeHandler(tracer, svc, logger), cfg.httpPort, cfg, logger)
})
err = <-errs
logger.Error(fmt.Sprintf("Twins service terminated: %s", err))
g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("Twins service shutdown by signal: %s", sig))
}
return nil
})
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("Twins service terminated: %s", err))
}
}
func loadConfig() config {
@ -310,14 +319,36 @@ func newService(ps messaging.PubSub, chanID string, users mainflux.AuthServiceCl
return svc
}
func startHTTPServer(handler http.Handler, port string, cfg config, logger logger.Logger, errs chan error) {
func startHTTPServer(ctx context.Context, handler http.Handler, port string, cfg config, logger logger.Logger) error {
p := fmt.Sprintf(":%s", port)
if cfg.serverCert != "" || cfg.serverKey != "" {
errCh := make(chan error)
server := &http.Server{Addr: p, Handler: handler}
switch {
case cfg.serverCert != "" || cfg.serverKey != "":
logger.Info(fmt.Sprintf("Twins service started using https on port %s with cert %s key %s",
port, cfg.serverCert, cfg.serverKey))
errs <- http.ListenAndServeTLS(p, cfg.serverCert, cfg.serverKey, handler)
return
go func() {
errCh <- server.ListenAndServeTLS(cfg.serverCert, cfg.serverKey)
}()
default:
logger.Info(fmt.Sprintf("Twins service started using http on port %s", cfg.httpPort))
go func() {
errCh <- server.ListenAndServe()
}()
}
select {
case <-ctx.Done():
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
defer cancelShutdown()
if err := server.Shutdown(ctxShutdown); err != nil {
logger.Error(fmt.Sprintf("Twins service error occurred during shutdown at %s: %s", p, err))
return fmt.Errorf("twins service occurred during shutdown at %s: %w", p, err)
}
logger.Info(fmt.Sprintf("Twins service shutdown of http at %s", p))
return nil
case err := <-errCh:
return err
}
logger.Info(fmt.Sprintf("Twins service started using http on port %s", cfg.httpPort))
errs <- http.ListenAndServe(p, handler)
}

View File

@ -11,10 +11,8 @@ import (
"log"
"net/http"
"os"
"os/signal"
"regexp"
"strconv"
"syscall"
"time"
"github.com/mainflux/mainflux/internal/email"
@ -24,6 +22,7 @@ import (
"github.com/mainflux/mainflux/users/bcrypt"
"github.com/mainflux/mainflux/users/emailer"
"github.com/mainflux/mainflux/users/tracing"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
@ -40,6 +39,8 @@ import (
)
const (
stopWaitTime = 5 * time.Second
defLogLevel = "error"
defDBHost = "localhost"
defDBPort = "5432"
@ -135,6 +136,8 @@ type config struct {
func main() {
cfg := loadConfig()
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
logger, err := logger.New(os.Stdout, cfg.logLevel)
if err != nil {
@ -158,18 +161,22 @@ func main() {
defer dbCloser.Close()
svc := newService(db, dbTracer, auth, cfg, logger)
errs := make(chan error, 2)
go startHTTPServer(tracer, svc, cfg.httpPort, cfg.serverCert, cfg.serverKey, logger, errs)
g.Go(func() error {
return startHTTPServer(ctx, tracer, svc, cfg.httpPort, cfg.serverCert, cfg.serverKey, logger)
})
go func() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
errs <- fmt.Errorf("%s", <-c)
}()
g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("Users service shutdown by signal: %s", sig))
}
return nil
})
err = <-errs
logger.Error(fmt.Sprintf("Users service terminated: %s", err))
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("Users service terminated: %s", err))
}
}
func loadConfig() config {
@ -411,13 +418,36 @@ func createAdmin(svc users.Service, userRepo users.UserRepository, c config, aut
return nil
}
func startHTTPServer(tracer opentracing.Tracer, svc users.Service, port string, certFile string, keyFile string, logger logger.Logger, errs chan error) {
func startHTTPServer(ctx context.Context, tracer opentracing.Tracer, svc users.Service, port string, certFile string, keyFile string, logger logger.Logger) error {
p := fmt.Sprintf(":%s", port)
if certFile != "" || keyFile != "" {
errCh := make(chan error)
server := &http.Server{Addr: p, Handler: api.MakeHandler(svc, tracer, logger)}
switch {
case certFile != "" || keyFile != "":
logger.Info(fmt.Sprintf("Users service started using https, cert %s key %s, exposed port %s", certFile, keyFile, port))
errs <- http.ListenAndServeTLS(p, certFile, keyFile, api.MakeHandler(svc, tracer, logger))
} else {
go func() {
errCh <- server.ListenAndServeTLS(certFile, keyFile)
}()
default:
logger.Info(fmt.Sprintf("Users service started using http, exposed port %s", port))
errs <- http.ListenAndServe(p, api.MakeHandler(svc, tracer, logger))
go func() {
errCh <- server.ListenAndServe()
}()
}
select {
case <-ctx.Done():
ctxShutdown, cancelShutdown := context.WithTimeout(context.Background(), stopWaitTime)
defer cancelShutdown()
if err := server.Shutdown(ctxShutdown); err != nil {
logger.Error(fmt.Sprintf("Users service error occurred during shutdown at %s: %s", p, err))
return fmt.Errorf("users service occurred during shutdown at %s: %w", p, err)
}
logger.Info(fmt.Sprintf("Users service shutdown of http at %s", p))
return nil
case err := <-errCh:
return err
}
}

View File

@ -3,6 +3,14 @@
package errors
import (
"context"
"fmt"
"os"
"os/signal"
"syscall"
)
// Error specifies an API that must be fullfiled by error type
type Error interface {
@ -94,3 +102,14 @@ func New(text string) Error {
err: nil,
}
}
func SignalHandler(ctx context.Context) error {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT, syscall.SIGABRT)
select {
case sig := <-c:
return fmt.Errorf("%s", sig)
case <-ctx.Done():
return nil
}
}