summaryrefslogtreecommitdiff
path: root/internal/service/util.go
blob: 3e4a7f35c0aad06f4a636399a81ee4840ec807a1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package service

import (
	"context"
	"fmt"
	"os"
	"os/signal"
	"sync"
	"syscall"

	"golang.org/x/sync/errgroup"
)

func RunAll(ctx Context) (err error) {
	provisioners := GetProvisioners()

	return Run(ctx, provisioners...)
}

func Run(ctx Context, provisioners ...Provisioner) (err error) {
	cctx, cancel := context.WithCancel(ctx)

	group, cctx := errgroup.WithContext(cctx)

	defer cancel()

	quit := make(chan os.Signal, 1)

	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)

	defer signal.Stop(quit)

	var (
		services []Provider
	)

	log := ctx.GetLogger()

	for _, provisioner := range provisioners {
		if service, err := provisioner(ctx); err != nil {
			return fmt.Errorf("error occurred provisioning services: %w", err)
		} else if service != nil {
			services = append(services, service)
		}
	}

	for _, service := range services {
		group.Go(service.Run)
	}

	log.Info("Startup complete")

	select {
	case s := <-quit:
		log.WithField("signal", s.String()).Debug("Shutdown initiated due to process signal")
	case <-cctx.Done():
		log.Debug("Shutdown initiated due to context completion")
	}

	cancel()

	log.Info("Shutdown initiated")

	wgShutdown := &sync.WaitGroup{}

	log.Tracef("Shutdown of %d services is required", len(services))

	for _, service := range services {
		wgShutdown.Add(1)

		go func(service Provider) {
			service.Log().Trace("Shutdown of service initiated")

			service.Shutdown()

			wgShutdown.Done()

			service.Log().Trace("Shutdown of service complete")
		}(service)
	}

	wgShutdown.Wait()

	if err = ctx.GetProviders().UserProvider.Close(); err != nil {
		ctx.GetLogger().WithError(err).Error("Error occurred closing authentication connections")
	}

	if err = ctx.GetProviders().StorageProvider.Close(); err != nil {
		log.WithError(err).Error("Error occurred closing database connections")
	}

	if err = group.Wait(); err != nil {
		log.WithError(err).Error("Error occurred waiting for shutdown")
	}

	log.Info("Shutdown complete")

	return nil
}

func connectionType(isTLS bool) string {
	if isTLS {
		return "TLS"
	}

	return "non-TLS"
}

func recoverErr(i any) error {
	switch v := i.(type) {
	case nil:
		return nil
	case string:
		return fmt.Errorf("recovered panic: %s", v)
	case error:
		return fmt.Errorf("recovered panic: %w", v)
	default:
		return fmt.Errorf("recovered panic with unknown type: %v", v)
	}
}