fix layout TODO fix workers packaging with skeris

This commit is contained in:
Pavel 2024-11-03 14:20:52 +03:00
parent 6375bbb24d
commit 101f9a2f18
33 changed files with 374 additions and 289 deletions

@ -1,216 +0,0 @@
package app
import (
"context"
"errors"
"fmt"
"github.com/go-redis/redis/v8"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
"github.com/skeris/appInit"
"github.com/themakers/hlog"
"go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/clients"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/answerwc"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/privilegewc"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/senders"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/workers/shortstat"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/workers/timeout"
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/customer_clients"
"time"
)
type App struct {
logger *zap.Logger
err chan error
}
func (a App) GetLogger() *zap.Logger {
return a.logger
}
func (a App) GetErr() chan error {
return a.err
}
var (
errInvalidOptions = errors.New("invalid options")
)
var zapOptions = []zap.Option{
zap.AddCaller(),
zap.AddCallerSkip(2),
zap.AddStacktrace(zap.ErrorLevel),
}
var _ appInit.CommonApp = (*App)(nil)
type Options struct {
ServiceName string `env:"SERVICE_NAME" default:"squiz"`
KafkaBroker string `env:"KAFKA_BROKER" default:"localhost:6379"`
KafkaTopic string `env:"KAFKA_TOPIC" default:"test-topic"`
LoggerProdMode bool `env:"IS_PROD_LOG" default:"false"`
IsProd bool `env:"IS_PROD" default:"false"`
MinioEP string `env:"MINIO_EP" default:"localhost:3002"`
MinioAK string `env:"MINIO_AK" default:"minio"`
MinioSK string `env:"MINIO_SK" default:"miniostorage"`
PostgresCredentials string `env:"PG_CRED" default:"host=localhost port=35432 user=squiz password=Redalert2 dbname=squiz sslmode=disable"`
RedisHost string `env:"REDIS_HOST" default:"localhost:6379"`
RedisPassword string `env:"REDIS_PASSWORD" default:"admin"`
RedisDB uint64 `env:"REDIS_DB" default:"2"`
SmtpHost string `env:"SMTP_HOST" default:"connect.mailclient.bz"`
SmtpPort string `env:"SMTP_PORT" default:"587"`
SmtpSender string `env:"SMTP_SENDER" default:"noreply@mailing.pena.digital"`
SmtpUsername string `env:"SMTP_USERNAME" default:"kotilion.95@gmail.com"`
SmtpPassword string `env:"SMTP_PASSWORD" default:"vWwbCSg4bf0p"`
SmtpApiKey string `env:"SMTP_API_KEY" default:"P0YsjUB137upXrr1NiJefHmXVKW1hmBWlpev"`
SmtpApiUrl string `env:"SMTP_API_URL" default:"https://api.smtp.bz/v1/smtp/send"`
CustomerServiceAddress string `env:"CUSTOMER_SERVICE_ADDRESS" default:"localhost:9001"`
TgToken string `env:"TG_TOKEN"`
}
func New(ctx context.Context, opts interface{}, ver appInit.Version) (appInit.CommonApp, error) {
var (
err, workerErr error
zapLogger *zap.Logger
errChan = make(chan error)
options Options
ok bool
)
if options, ok = opts.(Options); !ok {
return App{}, errInvalidOptions
}
if options.LoggerProdMode {
zapLogger, err = zap.NewProduction(zapOptions...)
if err != nil {
return nil, err
}
} else {
zapLogger, err = zap.NewDevelopment(zapOptions...)
if err != nil {
return nil, err
}
}
zapLogger = zapLogger.With(
zap.String("SvcCommit", ver.Commit),
zap.String("SvcVersion", ver.Release),
zap.String("SvcBuildTime", ver.BuildTime),
)
logger := hlog.New(zapLogger)
logger.Emit(InfoSvcStarted{})
zapLogger.Info("config", zap.Any("options", options))
go func() {
for {
select {
case <-ctx.Done():
return
case err := <-errChan:
zapLogger.Error("Ошибка при работе воркера", zap.Error(err))
}
}
}()
//init redis
redisClient := redis.NewClient(&redis.Options{
Addr: options.RedisHost,
Password: options.RedisPassword,
DB: int(options.RedisDB),
})
mailClent := clients.NewSmtpClient(clients.Deps{
SmtpHost: options.SmtpHost,
SmtpPort: options.SmtpPort,
SmtpSender: options.SmtpSender,
ApiKey: options.SmtpApiKey,
SmtpApiUrl: options.SmtpApiUrl,
})
// tgSender, err := senders.NewTgSender(options.TgToken)
// if err != nil {
// fmt.Println(err)
// return nil, err
// }
mailSender := senders.NewMailLeadSender(mailClent)
leadSenders := []senders.LeadSender{mailSender/* , tgSender */}
customerClient := customer_clients.NewCustomersClient(customer_clients.CustomersClientDeps{
Logger: zapLogger,
CustomerServiceHost: options.CustomerServiceAddress,
})
minioClient, err := minio.New(options.MinioEP, &minio.Options{
Creds: credentials.NewStaticV4(options.MinioAK, options.MinioSK, ""),
Secure: options.IsProd,
})
if err != nil {
fmt.Println("MINIOERR", options.MinioEP, err)
return nil, err
}
pgdal, err := dal.New(ctx, options.PostgresCredentials, minioClient)
if err != nil {
return nil, err
}
kafkaWorker, err := privilegewc.NewKafkaConsumerWorker(privilegewc.Config{
KafkaBroker: options.KafkaBroker,
KafkaTopic: options.KafkaTopic,
ServiceKey: options.ServiceName,
TickerInterval: time.Second * 10,
ErrChan: errChan,
}, redisClient, pgdal)
if err != nil {
logger.Module("Failed start privilege worker")
return nil, err
}
checkWorker := privilegewc.NewCheckWorker(privilegewc.Deps{
PrivilegeIDsDays: []string{"quizUnlimTime", "squizHideBadge"},
PrivilegeIDsCount: []string{"quizCnt", "quizManual"},
TickerInterval: time.Minute,
PrivilegeDAL: pgdal,
CustomerClient: customerClient,
}, errChan)
go kafkaWorker.Start(ctx)
go checkWorker.Start(ctx)
toClientWorker := answerwc.NewSendToClient(answerwc.DepsSendToClient{
Redis: redisClient,
Dal: pgdal,
LeadSenders: leadSenders,
CustomerService: customerClient,
}, errChan)
toRespWorker := answerwc.NewRespWorker(answerwc.DepsRespWorker{
Redis: redisClient,
Dal: pgdal,
MailClient: mailSender,
}, errChan)
go toClientWorker.Start(ctx)
go toRespWorker.Start(ctx)
tow := timeout.New(pgdal, time.Minute)
statW := shortstat.New(pgdal, 5*time.Minute)
tow.ExposeErr(ctx, &workerErr)
statW.ExposeErr(ctx, &workerErr)
go tow.Start(ctx)
go func() {
// defer pgdal.CloseWorker()
statW.Start(ctx)
}()
logger.Emit(InfoSvcReady{})
// todo implement helper func for service app type. such as server preparing, logger preparing, healthchecks and etc.
return &App{
logger: zapLogger,
err: make(chan error),
}, err
}

35
cmd/main.go Normal file

@ -0,0 +1,35 @@
package main
import (
"context"
"go.uber.org/zap"
"log"
"os"
"os/signal"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/internal/app"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/internal/initialize"
"syscall"
)
var (
commit string = os.Getenv("COMMIT")
buildTime string = os.Getenv("BUILD_TIME")
version string = os.Getenv("VERSION")
)
func main() {
config, err := initialize.LoadConfig()
if err != nil {
log.Fatal("Failed to load config", zap.Error(err))
}
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()
if err = app.New(ctx, *config, app.Build{
Commit: commit,
Version: version,
}); err != nil {
log.Fatal("App exited with error", zap.Error(err))
}
}

5
go.mod

@ -5,19 +5,20 @@ go 1.22.0
toolchain go1.22.2
require (
github.com/caarlos0/env/v8 v8.0.0
github.com/go-redis/redis/v8 v8.11.5
github.com/gofiber/fiber/v2 v2.52.4
github.com/golang/protobuf v1.5.4
github.com/joho/godotenv v1.5.1
github.com/minio/minio-go/v7 v7.0.69
github.com/pioz/faker v1.7.3
github.com/skeris/appInit v1.0.2
github.com/stretchr/testify v1.8.4
github.com/themakers/hlog v0.0.0-20191205140925-235e0e4baddf
github.com/twmb/franz-go v1.17.0
go.uber.org/zap v1.27.0
golang.org/x/net v0.27.0
gopkg.in/tucnak/telebot.v2 v2.5.0
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240926192151-a4340fff1688
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20241025130405-8ab347d96f1f
penahub.gitlab.yandexcloud.net/pena-services/customer v1.0.1-0.20240906192816-fac35dc869e6
)

45
go.sum

@ -1,10 +1,11 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/ClickHouse/clickhouse-go v1.5.4 h1:cKjXeYLNWVJIx2J1K6H2CqyRmfwVJVY1OV1coaaFcI0=
github.com/ClickHouse/clickhouse-go v1.5.4/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/bkaradzic/go-lz4 v1.0.0 h1:RXc4wYsyz985CkXXeX04y4VnZFGG8Rd43pRaHsOXAKk=
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
github.com/caarlos0/env/v8 v8.0.0 h1:POhxHhSpuxrLMIdvTGARuZqR4Jjm8AYmoi/JKlcScs0=
github.com/caarlos0/env/v8 v8.0.0/go.mod h1:7K4wMY9bH0esiXSSHlfHLX5xKGQMnkH5Fk4TDSSSzfo=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 h1:F1EaeKL/ta07PY/k9Os/UFtwERei2/XzGemhpGnBKNg=
@ -28,23 +29,20 @@ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@ -89,16 +87,12 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/skeris/appInit v1.0.2 h1:Hr4KbXYd6kolTVq4cXGqDpgnpmaauiOiKizA1+Ep4KQ=
github.com/skeris/appInit v1.0.2/go.mod h1:4ElEeXWVGzU3dlYq/eMWJ/U5hd+LKisc1z3+ySh1XmY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
@ -115,43 +109,23 @@ github.com/valyala/fasthttp v1.54.0 h1:cCL+ZZR3z3HPLMVfEYVUMtJqVaui0+gu7Lx63unHw
github.com/valyala/fasthttp v1.54.0/go.mod h1:6dt4/8olwq9QARP/TDuPmWyWcl4byhpvTJ4AAtcz+QM=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240730163845-b1a4ccb954bf h1:liao9UHurZLtiEwBgT9LMOnKYsHze6eA6w1KQCMVN2Q=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240730163845-b1a4ccb954bf/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
@ -159,10 +133,8 @@ google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjr
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
@ -175,14 +147,9 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240607202348-efe5f2bf3e8c h1:CWb4UcuNXhd1KTNOmy2U0TJO4+Qxgxrj5cwkyFqbgrk=
penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240607202348-efe5f2bf3e8c/go.mod h1:+bPxq2wfW5S1gd+83vZYmHm33AE7nEBfznWS8AM1TKE=
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240917072310-995a5f34a565 h1:E5AC+Fa5dUF5d71ihbaWSAH0GNuw7MTEZ7jUyBF5DSA=
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240917072310-995a5f34a565/go.mod h1:uOuosXduBzd2WbLH6TDZO7ME7ZextulA662oZ6OsoB0=
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240926181525-3f31028d5bf5 h1:dlICkNoE/NGFdfXujGq9OqvDibmE191IAxeUYCGOWVo=
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240926181525-3f31028d5bf5/go.mod h1:uOuosXduBzd2WbLH6TDZO7ME7ZextulA662oZ6OsoB0=
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240926192151-a4340fff1688 h1:VmfexzJInGgJ7ukwzXcS+OT8ikUCV4fIboN9pA2Nwm4=
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240926192151-a4340fff1688/go.mod h1:uOuosXduBzd2WbLH6TDZO7ME7ZextulA662oZ6OsoB0=
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20241025130405-8ab347d96f1f h1:HMXxbIkNmFeQTFI/MlsDBIRUTu8MTbn3i2PVcpQbXEI=
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20241025130405-8ab347d96f1f/go.mod h1:uOuosXduBzd2WbLH6TDZO7ME7ZextulA662oZ6OsoB0=
penahub.gitlab.yandexcloud.net/pena-services/customer v1.0.1-0.20240906192816-fac35dc869e6 h1:7DYT707HfYssFpeuPRJku8cGBFW7i+lyF9Ig4uFAYTs=
penahub.gitlab.yandexcloud.net/pena-services/customer v1.0.1-0.20240906192816-fac35dc869e6/go.mod h1:qKANJE2iOKIwDvxBQ6dWs7apmyuvNzqWIkPM8WdpgCI=

@ -7,15 +7,15 @@ import (
"github.com/go-redis/redis/v8"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/senders"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/wctools"
senders2 "penahub.gitlab.yandexcloud.net/backend/quiz/worker/internal/senders"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/internal/wctools"
"time"
)
type DepsRespWorker struct {
Redis *redis.Client
Dal *dal.DAL
MailClient *senders.MailLeadSender
MailClient *senders2.MailLeadSender
}
type RespWorker struct {
@ -128,7 +128,7 @@ func (w *RespWorker) processMessageToSMTP(quizConfig model.QuizConfig, questions
theme := quizConfig.Mailing.Theme
quizConfig.Mailing.Theme = quizConfig.Mailing.Reply
data := senders.TemplateData{
data := senders2.TemplateData{
QuizConfig: quizConfig.Mailing,
AnswerContent: answerContent,
AllAnswers: allAnswers,

@ -10,8 +10,8 @@ import (
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/pj_errors"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/senders"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/wctools"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/internal/senders"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/internal/wctools"
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/customer_clients"
"time"
)

163
internal/app/app.go Normal file

@ -0,0 +1,163 @@
package app
import (
"context"
"errors"
"github.com/themakers/hlog"
"go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
answerwc2 "penahub.gitlab.yandexcloud.net/backend/quiz/worker/internal/answerwc"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/internal/initialize"
privilegewc2 "penahub.gitlab.yandexcloud.net/backend/quiz/worker/internal/privilegewc"
senders2 "penahub.gitlab.yandexcloud.net/backend/quiz/worker/internal/senders"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/internal/workers/shortstat"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/internal/workers/timeout"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/pkg/closer"
"time"
)
var zapOptions = []zap.Option{
zap.AddCaller(),
zap.AddCallerSkip(2),
zap.AddStacktrace(zap.ErrorLevel),
}
type Build struct {
Commit string
Version string
}
func New(ctx context.Context, cfg initialize.Config, build Build) error {
var (
err, workerErr error
zapLogger *zap.Logger
errChan = make(chan error)
)
if cfg.LoggerProdMode {
zapLogger, err = zap.NewProduction(zapOptions...)
if err != nil {
return err
}
} else {
zapLogger, err = zap.NewDevelopment(zapOptions...)
if err != nil {
return err
}
}
zapLogger = zapLogger.With(
zap.String("SvcCommit", build.Commit),
zap.String("SvcVersion", build.Version),
zap.String("SvcBuildTime", time.Now().String()),
)
logger := hlog.New(zapLogger)
logger.Emit(InfoSvcStarted{})
shutdownGroup := closer.NewCloserGroup()
go func() {
for {
select {
case <-ctx.Done():
return
case err := <-errChan:
zapLogger.Error("Ошибка при работе воркера", zap.Error(err))
}
}
}()
redisClient, err := initialize.Redis(ctx, cfg)
if err != nil {
zapLogger.Error("failed init redis", zap.Error(err))
return err
}
minioClient, err := initialize.NewMinio(cfg)
if err != nil {
zapLogger.Error("failed init minio", zap.Error(err))
return err
}
clients := initialize.NewClients(cfg, zapLogger)
// tgSender, err := senders.NewTgSender(options.TgToken)
// if err != nil {
// fmt.Println(err)
// return nil, err
// }
mailSender := senders2.NewMailLeadSender(clients.MailClient)
leadSenders := []senders2.LeadSender{mailSender /* , tgSender */}
pgdal, err := dal.New(ctx, cfg.PostgresCredentials, minioClient)
if err != nil {
zapLogger.Error("failed init postgres", zap.Error(err))
return err
}
kafkaWorker, err := privilegewc2.NewKafkaConsumerWorker(privilegewc2.Config{
KafkaBroker: cfg.KafkaBroker,
KafkaTopic: cfg.KafkaTopic,
ServiceKey: cfg.ServiceName,
TickerInterval: time.Second * 10,
ErrChan: errChan,
}, redisClient, pgdal)
if err != nil {
zapLogger.Error("Failed start privilege worker", zap.Error(err))
return err
}
checkWorker := privilegewc2.NewCheckWorker(privilegewc2.Deps{
PrivilegeIDsDays: []string{"quizUnlimTime", "squizHideBadge"},
PrivilegeIDsCount: []string{"quizCnt", "quizManual"},
TickerInterval: time.Minute,
PrivilegeDAL: pgdal,
CustomerClient: clients.CustomerClient,
}, errChan)
go kafkaWorker.Start(ctx)
go checkWorker.Start(ctx)
toClientWorker := answerwc2.NewSendToClient(answerwc2.DepsSendToClient{
Redis: redisClient,
Dal: pgdal,
LeadSenders: leadSenders,
CustomerService: clients.CustomerClient,
}, errChan)
toRespWorker := answerwc2.NewRespWorker(answerwc2.DepsRespWorker{
Redis: redisClient,
Dal: pgdal,
MailClient: mailSender,
}, errChan)
go toClientWorker.Start(ctx)
go toRespWorker.Start(ctx)
tow := timeout.New(pgdal, time.Minute)
statW := shortstat.New(pgdal, 5*time.Minute)
tow.ExposeErr(ctx, &workerErr)
statW.ExposeErr(ctx, &workerErr)
go tow.Start(ctx)
go statW.Start(ctx)
logger.Emit(InfoSvcReady{})
shutdownGroup.Add(closer.CloserFunc(pgdal.Close))
<-ctx.Done()
timeoutCtx, timeoutCancel := context.WithTimeout(context.Background(), 10*time.Second)
defer timeoutCancel()
if err := shutdownGroup.Call(timeoutCtx); err != nil {
if errors.Is(err, context.DeadlineExceeded) {
zapLogger.Error("Shutdown timed out", zap.Error(err))
} else {
zapLogger.Error("Failed to shutdown services gracefully", zap.Error(err))
}
return err
}
zapLogger.Info("Application has stopped")
return nil
}

@ -0,0 +1,28 @@
package initialize
import (
"go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/clients"
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/customer_clients"
)
type Clients struct {
MailClient *clients.SmtpClient
CustomerClient *customer_clients.CustomersClient
}
func NewClients(cfg Config, logger *zap.Logger) *Clients {
return &Clients{
MailClient: clients.NewSmtpClient(clients.Deps{
SmtpHost: cfg.SmtpHost,
SmtpPort: cfg.SmtpPort,
SmtpSender: cfg.SmtpSender,
ApiKey: cfg.SmtpApiKey,
SmtpApiUrl: cfg.SmtpApiUrl,
}),
CustomerClient: customer_clients.NewCustomersClient(customer_clients.CustomersClientDeps{
Logger: logger,
CustomerServiceHost: cfg.CustomerServiceAddress,
}),
}
}

@ -0,0 +1,42 @@
package initialize
import (
"github.com/caarlos0/env/v8"
"github.com/joho/godotenv"
"log"
)
type Config struct {
ServiceName string `env:"SERVICE_NAME" envDefault:"squiz"`
KafkaBroker string `env:"KAFKA_BROKER" envDefault:"localhost:6379"`
KafkaTopic string `env:"KAFKA_TOPIC" envDefault:"test-topic"`
LoggerProdMode bool `env:"IS_PROD_LOG" envDefault:"false"`
IsProd bool `env:"IS_PROD" envDefault:"false"`
MinioEP string `env:"MINIO_EP" envDefault:"localhost:3002"`
MinioAK string `env:"MINIO_AK" envDefault:"minio"`
MinioSK string `env:"MINIO_SK" envDefault:"miniostorage"`
PostgresCredentials string `env:"PG_CRED" envDefault:"host=localhost port=35432 user=squiz password=Redalert2 dbname=squiz sslmode=disable"`
RedisHost string `env:"REDIS_HOST" envDefault:"localhost:6379"`
RedisPassword string `env:"REDIS_PASSWORD" envDefault:"admin"`
RedisDB uint64 `env:"REDIS_DB" envDefault:"2"`
SmtpHost string `env:"SMTP_HOST" envDefault:"connect.mailclient.bz"`
SmtpPort string `env:"SMTP_PORT" envDefault:"587"`
SmtpSender string `env:"SMTP_SENDER" envDefault:"noreply@mailing.pena.digital"`
SmtpUsername string `env:"SMTP_USERNAME" envDefault:"kotilion.95@gmail.com"`
SmtpPassword string `env:"SMTP_PASSWORD" envDefault:"vWwbCSg4bf0p"`
SmtpApiKey string `env:"SMTP_API_KEY" envDefault:"P0YsjUB137upXrr1NiJefHmXVKW1hmBWlpev"`
SmtpApiUrl string `env:"SMTP_API_URL" envDefault:"https://api.smtp.bz/v1/smtp/send"`
CustomerServiceAddress string `env:"CUSTOMER_SERVICE_ADDRESS" envDefault:"localhost:9001"`
TgToken string `env:"TG_TOKEN"`
}
func LoadConfig() (*Config, error) {
if err := godotenv.Load(); err != nil {
log.Print("No .env file found")
}
var config Config
if err := env.Parse(&config); err != nil {
return nil, err
}
return &config, nil
}

@ -0,0 +1,17 @@
package initialize
import (
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
)
func NewMinio(cfg Config) (*minio.Client, error) {
minioClient, err := minio.New(cfg.MinioEP, &minio.Options{
Creds: credentials.NewStaticV4(cfg.MinioAK, cfg.MinioSK, ""),
Secure: cfg.IsProd,
})
if err != nil {
return nil, err
}
return minioClient, nil
}

@ -0,0 +1,21 @@
package initialize
import (
"context"
"github.com/go-redis/redis/v8"
)
func Redis(ctx context.Context, cfg Config) (*redis.Client, error) {
rdb := redis.NewClient(&redis.Options{
Addr: cfg.RedisHost,
Password: cfg.RedisPassword,
DB: int(cfg.RedisDB),
})
status := rdb.Ping(ctx)
if err := status.Err(); err != nil {
return nil, err
}
return rdb, nil
}

@ -7,7 +7,7 @@ import (
"github.com/twmb/franz-go/pkg/kgo"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/wctools"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/internal/wctools"
"strings"
"time"
)

@ -5,7 +5,7 @@ import (
"database/sql"
"fmt"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/workers"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/internal/workers"
"time"
)

@ -4,7 +4,7 @@ import (
"context"
"database/sql"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/workers"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/internal/workers"
"time"
)

10
main.go

@ -1,10 +0,0 @@
package main
import (
"github.com/skeris/appInit"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/app"
)
func main() {
appInit.Initialize(app.New, app.Options{})
}

37
pkg/closer/closer.go Normal file

@ -0,0 +1,37 @@
package closer
import (
"context"
)
type Closer interface {
Close(ctx context.Context) error
}
type CloserFunc func(ctx context.Context) error
func (cf CloserFunc) Close(ctx context.Context) error {
return cf(ctx)
}
type CloserGroup struct {
closers []Closer
}
func NewCloserGroup() *CloserGroup {
return &CloserGroup{}
}
func (cg *CloserGroup) Add(c Closer) {
cg.closers = append(cg.closers, c)
}
func (cg *CloserGroup) Call(ctx context.Context) error {
var closeErr error
for i := len(cg.closers) - 1; i >= 0; i-- {
if err := cg.closers[i].Close(ctx); err != nil && closeErr == nil {
closeErr = err
}
}
return closeErr
}

@ -13,8 +13,8 @@ import (
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/clients"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/answerwc"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/senders"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/internal/answerwc"
senders2 "penahub.gitlab.yandexcloud.net/backend/quiz/worker/internal/senders"
"strings"
"testing"
"time"
@ -44,7 +44,7 @@ func TestProcessMessageToSMTP(t *testing.T) {
recipient := "pashamullin2001@gmail.com"
subject := "Test"
data := senders.TemplateData{
data := senders2.TemplateData{
QuizConfig: model.ResultInfo{
Theme: "<h1>Taemplste Quiz</h1>",
},
@ -76,7 +76,7 @@ func TestProcessMessageToSMTP(t *testing.T) {
AnswerTime: time.Now().Format("Monday, 2 January 2006 г., 15:04 UTC-07:00"),
}
mailSender := senders.NewMailLeadSender(client)
mailSender := senders2.NewMailLeadSender(client)
err := mailSender.SendMailWithAttachment(recipient, subject, toClientTemplate, data, nil)
if err != nil {
t.Errorf("Error sending email: %v", err)
@ -104,9 +104,9 @@ func TestProcessReminderToClient(t *testing.T) {
Theme: "Reminder Theme",
}
mailSender := senders.NewMailLeadSender(client)
mailSender := senders2.NewMailLeadSender(client)
err := mailSender.SendMailWithAttachment(recipient, subject, reminderTemplate, senders.TemplateData{
err := mailSender.SendMailWithAttachment(recipient, subject, reminderTemplate, senders2.TemplateData{
QuizConfig: quizConfig,
AnswerContent: model.ResultContent{},
AllAnswers: []model.ResultAnswer{},
@ -129,8 +129,8 @@ func TestProcessMessageToClient(t *testing.T) {
}
mailClient := clients.NewSmtpClient(smtpData)
mailSender := senders.NewMailLeadSender(mailClient)
tgSender, err := senders.NewTgSender("6712573453:AAFqTOsgwe_j48ZQ1GzWKQDT5Nwr-SAWjz8")
mailSender := senders2.NewMailLeadSender(mailClient)
tgSender, err := senders2.NewTgSender("6712573453:AAFqTOsgwe_j48ZQ1GzWKQDT5Nwr-SAWjz8")
assert.NoError(t, err)
ctx := context.Background()
@ -141,7 +141,7 @@ func TestProcessMessageToClient(t *testing.T) {
deps := answerwc.DepsSendToClient{
Redis: nil,
Dal: repo,
LeadSenders: []senders.LeadSender{mailSender, tgSender},
LeadSenders: []senders2.LeadSender{mailSender, tgSender},
CustomerService: nil,
}

@ -3,19 +3,19 @@ package tests
import (
"github.com/stretchr/testify/assert"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
"penahub.gitlab.yandexcloud.net/backend/quiz/worker/senders"
senders2 "penahub.gitlab.yandexcloud.net/backend/quiz/worker/internal/senders"
"testing"
"time"
)
func Test_Tg_Sender(t *testing.T) {
tg_Sender, err := senders.NewTgSender("6712573453:AAFqTOsgwe_j48ZQ1GzWKQDT5Nwr-SAWjz8")
tg_Sender, err := senders2.NewTgSender("6712573453:AAFqTOsgwe_j48ZQ1GzWKQDT5Nwr-SAWjz8")
assert.NoError(t, err)
err = tg_Sender.SendLead(senders.LeadData{
err = tg_Sender.SendLead(senders2.LeadData{
To: int64(-1002217604546),
Subject: "test_TG_Sender",
Template: tgClientTemplate,
TemplateData: senders.TemplateData{
TemplateData: senders2.TemplateData{
QuizConfig: model.ResultInfo{
Theme: "Taemplste Quiz",
},