/
run.go
141 lines (114 loc) · 3.98 KB
/
run.go
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package service
import (
"context"
"fmt"
"log"
"os"
"os/signal"
"syscall"
"time"
"github.com/go-redis/redis/v8"
wormscanNotionalCache "github.com/wormhole-foundation/wormhole-explorer/common/client/cache/notional"
"github.com/wormhole-foundation/wormhole-explorer/common/dbutil"
"github.com/wormhole-foundation/wormhole-explorer/common/domain"
health "github.com/wormhole-foundation/wormhole-explorer/common/health"
"github.com/wormhole-foundation/wormhole-explorer/common/logger"
"github.com/wormhole-foundation/wormhole-explorer/notional/config"
"github.com/wormhole-foundation/wormhole-explorer/notional/http/infrastructure"
"github.com/wormhole-foundation/wormhole-explorer/notional/prices"
"go.mongodb.org/mongo-driver/mongo"
"go.uber.org/zap"
)
type exitCode int
func handleExit() {
if r := recover(); r != nil {
if e, ok := r.(exitCode); ok {
os.Exit(int(e))
}
panic(r) // not an Exit, bubble up
}
}
func Run() {
defer handleExit()
rootCtx, rootCtxCancel := context.WithCancel(context.Background())
// load configuration
config, err := config.New(rootCtx)
if err != nil {
log.Fatal("Error creating config", err)
}
// build logger
logger := logger.New("wormhole-notional", logger.WithLevel(config.LogLevel))
logger.Info("starting notional service...")
// setup DB connection
logger.Info("connecting to MongoDB...")
db, err := dbutil.Connect(rootCtx, logger, config.MongodbURI, config.MongodbDatabase, false)
if err != nil {
logger.Fatal("failed to connect MongoDB", zap.Error(err))
}
// get health check functions.
logger.Info("creating health check functions...")
healthChecks, err := newHealthChecks(rootCtx, config, db.Database)
if err != nil {
logger.Fatal("failed to create health checks", zap.Error(err))
}
//create notional cache
logger.Info("initializing notional cache...")
notionalCache, err := newNotionalCache(rootCtx, config, logger)
if err != nil {
logger.Fatal("failed to create notional cache", zap.Error(err))
}
// create token provider
tokenProvider := domain.NewTokenProvider(config.P2pNetwork)
//create repositories
repository := prices.NewPriceRepository(db.Database, logger)
//create services
priceService := prices.NewPriceService(repository, tokenProvider, notionalCache, logger)
//create controllers
priceController := prices.NewController(priceService, logger)
// create and start server.
logger.Info("initializing infrastructure server...")
server := infrastructure.NewServer(logger, config.Port, config.PprofEnabled, priceController, healthChecks...)
server.Start()
// Waiting for signal
logger.Info("waiting for termination signal or context cancellation...")
sigterm := make(chan os.Signal, 1)
signal.Notify(sigterm, syscall.SIGINT, syscall.SIGTERM)
select {
case <-rootCtx.Done():
logger.Warn("terminating (root context cancelled)")
case signal := <-sigterm:
logger.Info("terminating (signal received)", zap.String("signal", signal.String()))
}
logger.Info("cancelling root context...")
rootCtxCancel()
logger.Info("closing HTTP server...")
server.Stop()
logger.Info("closing MongoDB connection...")
db.DisconnectWithTimeout(10 * time.Second)
logger.Info("terminated successfully")
}
func newHealthChecks(
ctx context.Context,
config *config.Configuration,
db *mongo.Database,
) ([]health.Check, error) {
healthChecks := []health.Check{
health.Mongo(db),
}
return healthChecks, nil
}
func newNotionalCache(
ctx context.Context,
cfg *config.Configuration,
logger *zap.Logger,
) (wormscanNotionalCache.NotionalLocalCacheReadable, error) {
// use a distributed cache and for notional a pubsub to sync local cache.
redisClient := redis.NewClient(&redis.Options{Addr: cfg.CacheURL})
// get notional cache client and init load to local cache
notionalCache, err := wormscanNotionalCache.NewNotionalCache(ctx, redisClient, cfg.CachePrefix, cfg.CacheChannel, logger)
if err != nil {
return nil, fmt.Errorf("failed to create notional cache client: %w", err)
}
notionalCache.Init(ctx)
return notionalCache, nil
}