Added wait-for-it.sh script and fetching config from consul KV store
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Piotr Biernat 2022-12-07 02:51:47 +01:00
parent 7e938e3070
commit f2f8a40bd9
13 changed files with 330 additions and 43 deletions

View File

@ -1,11 +1,12 @@
# Builder # Builder
ARG BUILDER_IMAGE="git.pbiernat.dev/egommerce/order-builder:latest" ARG BUILDER_IMAGE
FROM ${BUILDER_IMAGE} AS builder FROM ${BUILDER_IMAGE} AS builder
# Destination image - server # Destination image - server
# FROM gcr.io/distroless/base-debian10 # FROM gcr.io/distroless/base-debian10
FROM alpine:3.17 FROM alpine:3.17
ARG BUILD_TIME
ARG BIN_OUTPUT ARG BIN_OUTPUT
ARG SVC_NAME ARG SVC_NAME
ARG SVC_VER ARG SVC_VER
@ -14,10 +15,15 @@ LABEL dev.egommerce.image.author="Piotr Biernat"
LABEL dev.egommerce.image.vendor="Egommerce" LABEL dev.egommerce.image.vendor="Egommerce"
LABEL dev.egommerce.image.service=${SVC_NAME} LABEL dev.egommerce.image.service=${SVC_NAME}
LABEL dev.egommerce.image.version=${SVC_VER} LABEL dev.egommerce.image.version=${SVC_VER}
LABEL dev.egommerce.image.build_time=${BUILD_TIME}
WORKDIR / WORKDIR /
COPY --from=builder $BIN_OUTPUT /app COPY --from=builder $BIN_OUTPUT /app
COPY .env.dist /.env COPY .env.dist /.env
COPY ./bin/entrypoint.sh ./bin/wait-for-it.sh /
RUN chmod 755 /entrypoint.sh
EXPOSE 80 EXPOSE 80
ENTRYPOINT ["/app"]
CMD ["/app"]
ENTRYPOINT ["/entrypoint.sh"]

25
bin/entrypoint.sh Executable file
View File

@ -0,0 +1,25 @@
#!/usr/bin/env sh
set +e
waitForService()
{
./wait-for-it.sh $1 -t 2 1>/dev/null 2>&1
status=$?
while [ $status != 0 ]
do
echo "[x] wating for $1..."
sleep 1
./wait-for-it.sh $1 -t 2 1>/dev/null 2>&1
status=$?
done
}
waitForService "postgres-db:5432"
waitForService "api-eventbus:5672"
waitForService "api-logger:24224"
waitForService "api-registry:8500"
set -euo pipefail
exec "$@"

165
bin/wait-for-it.sh Executable file
View File

@ -0,0 +1,165 @@
#!/usr/bin/env sh
# Use this script to test if a given TCP host/port are available
set -e
cmdname=$(basename "$0")
echoerr() {
if [ "$QUIET" -ne 1 ]; then
printf "%s\n" "$*" 1>&2;
fi
}
usage()
{
exitcode="$1"
cat << USAGE >&2
Usage:
$cmdname host:port [-s] [-t timeout] [-- command args]
-h HOST | --host=HOST Host or IP under test
-p PORT | --port=PORT TCP port under test
Alternatively, you specify the host and port as host:port
-s | --strict Only execute subcommand if the test succeeds
-q | --quiet Don't output any status messages
-t TIMEOUT | --timeout=TIMEOUT
Timeout in seconds, zero for no timeout
-- COMMAND ARGS Execute command with args after the test finishes
USAGE
exit "$exitcode"
}
wait_for()
{
if [ "$TIMEOUT" -gt 0 ]; then
echoerr "$cmdname: waiting $TIMEOUT seconds for $HOST:$PORT"
else
echoerr "$cmdname: waiting for $HOST:$PORT without a timeout"
fi
start_ts=$(date +%s)
while true
do
nc -z "$HOST" "$PORT" >/dev/null 2>&1
result=$?
if [ $result -eq 0 ]; then
end_ts=$(date +%s)
echoerr "$cmdname: $HOST:$PORT is available after $((end_ts - start_ts)) seconds"
break
fi
sleep 1
done
return $result
}
wait_for_wrapper()
{
# In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
if [ "$QUIET" -eq 1 ]; then
timeout "$TIMEOUT" "$0" -q -child "$HOST":"$PORT" -t "$TIMEOUT" &
else
timeout "$TIMEOUT" "$0" --child "$HOST":"$PORT" -t "$TIMEOUT" &
fi
PID=$!
trap 'kill -INT -$PID' INT
wait $PID
RESULT=$?
if [ $RESULT -ne 0 ]; then
echoerr "$cmdname: timeout occurred after waiting $TIMEOUT seconds for $HOST:$PORT"
fi
return $RESULT
}
TIMEOUT=15
STRICT=0
CHILD=0
QUIET=0
# process arguments
while [ $# -gt 0 ]
do
case "$1" in
*:* )
HOST=$(printf "%s\n" "$1"| cut -d : -f 1)
PORT=$(printf "%s\n" "$1"| cut -d : -f 2)
shift 1
;;
--child)
CHILD=1
shift 1
;;
-q | --quiet)
QUIET=1
shift 1
;;
-s | --strict)
STRICT=1
shift 1
;;
-h)
HOST="$2"
if [ "$HOST" = "" ]; then break; fi
shift 2
;;
--host=*)
HOST=$(printf "%s" "$1" | cut -d = -f 2)
shift 1
;;
-p)
PORT="$2"
if [ "$PORT" = "" ]; then break; fi
shift 2
;;
--port=*)
PORT="${1#*=}"
shift 1
;;
-t)
TIMEOUT="$2"
if [ "$TIMEOUT" = "" ]; then break; fi
shift 2
;;
--timeout=*)
TIMEOUT="${1#*=}"
shift 1
;;
--)
shift
break
;;
--help)
usage 0
;;
*)
echoerr "Unknown argument: $1"
usage 1
;;
esac
done
if [ "$HOST" = "" -o "$PORT" = "" ]; then
echoerr "Error: you need to provide a host and port to test."
usage 2
fi
if [ $CHILD -gt 0 ]; then
wait_for
RESULT=$?
exit $RESULT
else
if [ "$TIMEOUT" -gt 0 ]; then
wait_for_wrapper
RESULT=$?
else
wait_for
RESULT=$?
fi
fi
if [ "$*" != "" ]; then
if [ $RESULT -ne 0 -a $STRICT -eq 1 ]; then
echoerr "$cmdname: strict mode, refusing to execute subprocess"
exit $RESULT
fi
exec "$@"
else
exit $RESULT
fi

View File

@ -2,39 +2,39 @@
# RUN IN REPO ROOT DIR !! # RUN IN REPO ROOT DIR !!
export IMAGE_PREFIX="git.pbiernat.dev/egommerce/order" export IMAGE_PREFIX="git.pbiernat.dev/egommerce/order"
export BUILDER_IMAGE="$IMAGE_PREFIX-builder:tmp" export BUILDER_IMAGE="egommerce-builder:order"
export BUILD_TIME=$(date +"%Y%m%d%H%M%S")
export SERVER_IMAGE="$IMAGE_PREFIX-svc" export SERVER_IMAGE="$IMAGE_PREFIX-svc"
export WORKER_IMAGE="$IMAGE_PREFIX-worker" export WORKER_IMAGE="$IMAGE_PREFIX-worker"
export DOCKER_BUILDKIT=1
TARGET=${1:-latest} TARGET=${1:-latest}
[ ! -d \"src/vendor\" ] && sh -c "cd src; go mod vendor" [ ! -d "src/vendor" ] && sh -c "cd src; go mod vendor"
export DOCKER_BUILDKIT=1
docker build -t "$BUILDER_IMAGE" -f Dockerfile.builder . && echo "Successfully tagged $BUILDER_IMAGE"
echo "Building target $IMAGE_PREFIX images..." echo "Building target $IMAGE_PREFIX images..."
docker build --rm -t "$BUILDER_IMAGE" -f Dockerfile.builder .
if [ $TARGET = "latest" ] if [ $TARGET = "latest" ]
then then
# SERVER # SERVER
docker build --build-arg SVC_NAME=order-svc --build-arg SVC_VER="1.0" --build-arg BIN_OUTPUT=/go/bin/server \ docker build --build-arg SVC_NAME=order-svc --build-arg SVC_VER="1.0" --build-arg BIN_OUTPUT=/go/bin/server \
--rm --build-arg BUILDER_IMAGE --cache-from "$SERVER_IMAGE:$TARGET" -t "$SERVER_IMAGE:$TARGET" \ --build-arg BUILDER_IMAGE=$BUILDER_IMAGE --build-arg BUILD_TIME --rm --cache-from "$SERVER_IMAGE:$TARGET" -t "$SERVER_IMAGE:$TARGET" \
-f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $SERVER_IMAGE:$TARGET" & -f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $SERVER_IMAGE:$TARGET"
# WORKER # WORKER
docker build --build-arg SVC_NAME=order-worker --build-arg SVC_VER="1.0" --build-arg BIN_OUTPUT=/go/bin/worker \ docker build --build-arg SVC_NAME=order-worker --build-arg SVC_VER="1.0" --build-arg BIN_OUTPUT=/go/bin/worker \
--rm --build-arg BUILDER_IMAGE --cache-from "$WORKER_IMAGE:$TARGET" -t "$WORKER_IMAGE:$TARGET" \ --build-arg BUILDER_IMAGE=$BUILDER_IMAGE --build-arg BUILD_TIME --rm --cache-from "$WORKER_IMAGE:$TARGET" -t "$WORKER_IMAGE:$TARGET" \
-f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $WORKER_IMAGE:$TARGET" -f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $WORKER_IMAGE:$TARGET"
else else
# SERVER # SERVER
docker build --build-arg SVC_NAME=order-svc --build-arg SVC_VER="dev" --build-arg BIN_OUTPUT=/go/bin/server \ docker build --build-arg SVC_NAME=order-svc --build-arg SVC_VER="dev" --build-arg BIN_OUTPUT=/go/bin/server \
--rm --build-arg BUILDER_IMAGE --no-cache -t "$SERVER_IMAGE:$TARGET" \ --build-arg BUILDER_IMAGE=$BUILDER_IMAGE --build-arg BUILD_TIME --rm --no-cache -t "$SERVER_IMAGE:$TARGET" \
-f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $SERVER_IMAGE:$TARGET" & -f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $SERVER_IMAGE:$TARGET"
# WORKER # WORKER
docker build --build-arg SVC_NAME=order-worker --build-arg SVC_VER="dev" --build-arg BIN_OUTPUT=/go/bin/worker \ docker build --build-arg SVC_NAME=order-worker --build-arg SVC_VER="dev" --build-arg BIN_OUTPUT=/go/bin/worker \
--rm --build-arg BUILDER_IMAGE --no-cache -t "$WORKER_IMAGE:$TARGET" \ --build-arg BUILDER_IMAGE=$BUILDER_IMAGE --build-arg BUILD_TIME --rm --no-cache -t "$WORKER_IMAGE:$TARGET" \
-f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $WORKER_IMAGE:$TARGET" -f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $WORKER_IMAGE:$TARGET"
fi fi

View File

@ -8,5 +8,6 @@ export WORKER_IMAGE="$IMAGE_BASE-worker"
TARGET=${1:-latest} TARGET=${1:-latest}
echo $DOCKER_PASSWORD | docker login git.pbiernat.dev -u $DOCKER_USERNAME --password-stdin echo $DOCKER_PASSWORD | docker login git.pbiernat.dev -u $DOCKER_USERNAME --password-stdin
docker push "$SERVER_IMAGE:$TARGET" docker push "$SERVER_IMAGE:$TARGET"
docker push "$WORKER_IMAGE:$TARGET" docker push "$WORKER_IMAGE:$TARGET"

View File

@ -23,6 +23,7 @@ const (
defEventBusURL = "amqp://guest:guest@api-eventbus:5672" defEventBusURL = "amqp://guest:guest@api-eventbus:5672"
ebEventsExchange = "api-events" ebEventsExchange = "api-events"
ebEventsQueue = "order-svc" ebEventsQueue = "order-svc"
defKVNmspc = "dev.egommerce/service/order-svc"
) )
func main() { func main() {
@ -41,6 +42,7 @@ func main() {
c.DbURL = config.GetEnv("DATABASE_URL", defDbURL) c.DbURL = config.GetEnv("DATABASE_URL", defDbURL)
c.EventBusURL = config.GetEnv("EVENTBUS_URL", defEventBusURL) c.EventBusURL = config.GetEnv("EVENTBUS_URL", defEventBusURL)
c.EventBusExchange = ebEventsExchange c.EventBusExchange = ebEventsExchange
c.KVNamespace = config.GetEnv("APP_KV_NAMESPACE", defKVNmspc)
logHost, logPort := fluentd.ParseAddr(c.LoggerAddr) logHost, logPort := fluentd.ParseAddr(c.LoggerAddr)
logger := fluentd.NewLogger(c.GetAppFullName(), logHost, logPort) logger := fluentd.NewLogger(c.GetAppFullName(), logHost, logPort)

View File

@ -1,13 +1,18 @@
package main package main
import ( import (
"bytes"
"encoding/json"
"errors"
"fmt" "fmt"
"log" "log"
"os" "os"
"os/signal" "os/signal"
"strings" "strings"
"syscall" "syscall"
"time"
discovery "git.pbiernat.dev/egommerce/go-api-pkg/consul"
"git.pbiernat.dev/egommerce/go-api-pkg/fluentd" "git.pbiernat.dev/egommerce/go-api-pkg/fluentd"
amqp "git.pbiernat.dev/egommerce/go-api-pkg/rabbitmq" amqp "git.pbiernat.dev/egommerce/go-api-pkg/rabbitmq"
"git.pbiernat.dev/egommerce/order-service/internal/app/config" "git.pbiernat.dev/egommerce/order-service/internal/app/config"
@ -25,6 +30,7 @@ const (
defEventBusURL = "amqp://guest:guest@api-eventbus:5672" defEventBusURL = "amqp://guest:guest@api-eventbus:5672"
ebEventsExchange = "api-events" ebEventsExchange = "api-events"
ebEventsQueue = "order-worker" ebEventsQueue = "order-worker"
defKVNmspc = "dev.egommerce/service/order-worker"
) )
func main() { func main() {
@ -41,11 +47,28 @@ func main() {
c.EventBusURL = config.GetEnv("EVENTBUS_URL", defEventBusURL) c.EventBusURL = config.GetEnv("EVENTBUS_URL", defEventBusURL)
c.EventBusExchange = ebEventsExchange c.EventBusExchange = ebEventsExchange
c.EventBusQueue = ebEventsQueue c.EventBusQueue = ebEventsQueue
c.KVNamespace = config.GetEnv("APP_KV_NAMESPACE", defKVNmspc)
logHost, logPort := fluentd.ParseAddr(c.LoggerAddr) logHost, logPort := fluentd.ParseAddr(c.LoggerAddr)
logger := fluentd.NewLogger(c.GetAppFullName(), logHost, logPort) logger := fluentd.NewLogger(c.GetAppFullName(), logHost, logPort)
defer logger.Close() defer logger.Close()
consul, err := discovery.NewService(c.RegistryAddr, c.AppID, c.AppName, c.AppID, "", 0)
if err != nil {
logger.Log("Error connecting to %s: %v", c.RegistryAddr, err)
}
go func(consul *discovery.Service) {
interval := time.Second * 3
ticker := time.NewTicker(interval)
for range ticker.C {
err := updateKVConfig(consul, c) // FIXME: duplicated in internal/app/server/server.go
if err != nil {
logger.Log("KV config update error (skipping): %v\n", err)
}
}
}(consul)
// db conn // db conn
dbConn, err := database.Connect(c.DbURL) dbConn, err := database.Connect(c.DbURL)
if err != nil { // fixme: add wait-for-db... if err != nil { // fixme: add wait-for-db...
@ -142,3 +165,22 @@ func main() {
logger.Log("Waiting for messages...") logger.Log("Waiting for messages...")
<-forever <-forever
} }
func updateKVConfig(s *discovery.Service, oldCnf *server.Config) error { // FIXME: duplicated in internal/app/server/server.go
data, _, err := s.KV().Get(oldCnf.KVNamespace, nil)
if err != nil {
return err
}
if data == nil {
return errors.New("empty KV config data. Skipping")
}
buf := bytes.NewBuffer(data.Value)
decoder := json.NewDecoder(buf)
if err := decoder.Decode(oldCnf); err != nil {
return err
}
return nil
}

View File

@ -3,7 +3,7 @@ module git.pbiernat.dev/egommerce/order-service
go 1.18 go 1.18
require ( require (
git.pbiernat.dev/egommerce/go-api-pkg v0.0.101 git.pbiernat.dev/egommerce/go-api-pkg v0.0.108
github.com/gofiber/fiber/v2 v2.40.1 github.com/gofiber/fiber/v2 v2.40.1
github.com/jackc/pgx/v4 v4.17.2 github.com/jackc/pgx/v4 v4.17.2
github.com/joho/godotenv v1.4.0 github.com/joho/godotenv v1.4.0

View File

@ -1,13 +1,13 @@
git.pbiernat.dev/egommerce/go-api-pkg v0.0.32 h1:ArB/n30m927WMAM4u51guH+qR0Lu4NGyYnYdi7OhlzY= git.pbiernat.dev/egommerce/go-api-pkg v0.0.103 h1:tVSHVQOBDe1Ofcbodaa/R5gHRD4gYO/d1tw7rVuLJuA=
git.pbiernat.dev/egommerce/go-api-pkg v0.0.32/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= git.pbiernat.dev/egommerce/go-api-pkg v0.0.103/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8=
git.pbiernat.dev/egommerce/go-api-pkg v0.0.33 h1:1tm+pvUeS6OZLvHmLM3BwFS0Ty/eA3jDRuB60OicosA= git.pbiernat.dev/egommerce/go-api-pkg v0.0.104 h1:YymR7Zyo9xjIZ9S75o2nfyNHp69n2FXHyGbTxtV1p/A=
git.pbiernat.dev/egommerce/go-api-pkg v0.0.33/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= git.pbiernat.dev/egommerce/go-api-pkg v0.0.104/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8=
git.pbiernat.dev/egommerce/go-api-pkg v0.0.34 h1:UO1x6O+cyU7yYYbDCDyhhAypuf4QGIXcmWcBEEjLuYM= git.pbiernat.dev/egommerce/go-api-pkg v0.0.105 h1:8w4p4QNaSF58iL3YiGvqXC4UjUVeeu5D10OQmImA/Z0=
git.pbiernat.dev/egommerce/go-api-pkg v0.0.34/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= git.pbiernat.dev/egommerce/go-api-pkg v0.0.105/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8=
git.pbiernat.dev/egommerce/go-api-pkg v0.0.100 h1:jw4fiGbZTsfJXJpGV+HQiYeMGZ7DMRMoepjuIwY6FIU= git.pbiernat.dev/egommerce/go-api-pkg v0.0.106 h1:kOqDvQfk8MzmyQonMMLmZKhW7I5YeDyw6N8YIYHIVwA=
git.pbiernat.dev/egommerce/go-api-pkg v0.0.100/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= git.pbiernat.dev/egommerce/go-api-pkg v0.0.106/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8=
git.pbiernat.dev/egommerce/go-api-pkg v0.0.101 h1:NZCFAAlC94+LcN1gjrENnWUHvpWgaNksyB2N4Fiy8C4= git.pbiernat.dev/egommerce/go-api-pkg v0.0.108 h1:gr5kzKNR3sCxTz+nbqtOM7vdIely5ZWb8itSLAjTo0I=
git.pbiernat.dev/egommerce/go-api-pkg v0.0.101/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= git.pbiernat.dev/egommerce/go-api-pkg v0.0.108/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=

View File

@ -3,18 +3,24 @@ package server
import "fmt" import "fmt"
type Config struct { type Config struct {
AppID string AppID string
AppName string AppName string
AppDomain string AppDomain string
NetAddr string NetAddr string
Port int Port int
LoggerAddr string RegistryAddr string
RegistryAddr string KVNamespace string
DbURL string
MongoDbUrl string LoggerAddr string `json:"logger_addr"`
EventBusURL string DbURL string `json:"db_url"`
EventBusExchange string MongoDbUrl string `json:"mongodb_url"`
EventBusQueue string EventBusURL string `json:"eventbus_url"`
EventBusExchange string `json:"eventbus_exchange"`
EventBusQueue string `json:"eventbus_queue"`
HttpReadTimeout int `json:"http_read_timeout"`
HttpWriteTimeout int `json:"http_write_timeout"`
HttpIdleTimeout int `json:"http_idle_timeout"`
// Fields with json mapping are available trough ConsulKV
} }
func (c *Config) GetAppFullName() string { func (c *Config) GetAppFullName() string {

View File

@ -11,3 +11,7 @@ func (s *Server) HealthHandler(c *fiber.Ctx) error {
Status: "OK", Status: "OK",
}) })
} }
func (s *Server) ConfigHandler(c *fiber.Ctx) error {
return c.JSON(s.conf)
}

View File

@ -8,12 +8,13 @@ import (
) )
func SetupRoutes(s *Server) { func SetupRoutes(s *Server) {
s.App.Get("/health", s.HealthHandler)
s.App.Get("/config", s.ConfigHandler)
api := s.App.Group("/api") api := s.App.Group("/api")
v1 := api.Group("/v1") v1 := api.Group("/v1")
order := v1.Group("/order") order := v1.Group("/order")
order.Put("/:orderId/status", s.UpdateOrderStatusHandler) order.Put("/:orderId/status", s.UpdateOrderStatusHandler)
s.App.Get("/health", s.HealthHandler)
} }
func SetupMiddlewares(s *Server) { func SetupMiddlewares(s *Server) {

View File

@ -1,6 +1,9 @@
package server package server
import ( import (
"bytes"
"encoding/json"
"fmt"
"os" "os"
"os/signal" "os/signal"
"syscall" "syscall"
@ -16,12 +19,14 @@ import (
type Server struct { type Server struct {
*fiber.App *fiber.App
conf *Config
log *fluentd.Logger log *fluentd.Logger
db *pgxpool.Pool db *pgxpool.Pool
ebCh *amqp.Channel ebCh *amqp.Channel
discovery *discovery.Service discovery *discovery.Service
name string name string
addr string addr string
kvNmspc string
} }
type Headers struct { type Headers struct {
@ -30,13 +35,13 @@ type Headers struct {
func NewServer(conf *Config, logger *fluentd.Logger, db *pgxpool.Pool, ebCh *amqp.Channel) *Server { func NewServer(conf *Config, logger *fluentd.Logger, db *pgxpool.Pool, ebCh *amqp.Channel) *Server {
logger.Log("API_ID: %s", conf.AppID) logger.Log("API_ID: %s", conf.AppID)
discovery, err := discovery.NewService(conf.RegistryAddr, conf.AppID, conf.AppName, conf.AppID, conf.AppDomain, conf.Port) consul, err := discovery.NewService(conf.RegistryAddr, conf.AppID, conf.AppName, conf.AppID, conf.AppDomain, conf.Port)
if err != nil { if err != nil {
logger.Log("Error connecting to %s: %v", conf.RegistryAddr, err) logger.Log("Error connecting to %s: %v", conf.RegistryAddr, err)
} }
logger.Log("Registering service with name: %s, address: %s", discovery.Name, discovery.Address) logger.Log("Registering service with name: %s, address: %s", consul.Name, consul.Address)
err = discovery.Register() err = consul.Register()
if err != nil { if err != nil {
logger.Log("register error: %v", err) logger.Log("register error: %v", err)
} }
@ -50,14 +55,27 @@ func NewServer(conf *Config, logger *fluentd.Logger, db *pgxpool.Pool, ebCh *amq
} }
s := &Server{ s := &Server{
fiber.New(cnf), fiber.New(cnf),
conf,
logger, logger,
db, db,
ebCh, ebCh,
discovery, consul,
conf.AppName, conf.AppName,
conf.NetAddr, conf.NetAddr,
conf.KVNamespace,
} }
go func(s *Server) { // Consul KV config updater
interval := time.Second * 30
ticker := time.NewTicker(interval)
for range ticker.C {
err := s.updateKVConfig()
if err != nil {
logger.Log("KV config update error (skipping): %v\n", err)
}
}
}(s)
SetupMiddlewares(s) SetupMiddlewares(s)
SetupRoutes(s) SetupRoutes(s)
@ -98,6 +116,23 @@ func (s *Server) GetRequestID(c *fiber.Ctx) (string, error) {
return hdr.RequestID, nil return hdr.RequestID, nil
} }
func (s *Server) updateKVConfig() error { // FIXME: duplicated in cmd/worker/main.go
data, _, err := s.discovery.KV().Get(s.kvNmspc, nil)
if err != nil {
fmt.Println(err)
return err
}
kvCnf := bytes.NewBuffer(data.Value)
decoder := json.NewDecoder(kvCnf)
if err := decoder.Decode(&s.conf); err != nil {
return err
}
return nil
}
func (s *Server) gracefulShutdown() error { func (s *Server) gracefulShutdown() error {
s.log.Log("Server is going down...") s.log.Log("Server is going down...")
s.log.Log("Unregistering service: %s", s.discovery.GetID()) s.log.Log("Unregistering service: %s", s.discovery.GetID())