task-processor/internal/app/app.go

188 lines
4.2 KiB
Go
Raw Normal View History

2025-10-02 20:35:53 +03:00
package app
import (
"context"
log "github.com/sirupsen/logrus"
2026-02-28 10:53:33 +03:00
"google.golang.org/grpc"
2025-10-02 20:35:53 +03:00
"net"
"runtime"
2025-10-03 19:17:01 +03:00
"task-processor/config"
"task-processor/internal/appState"
"task-processor/internal/parsers"
2025-12-26 16:19:09 +03:00
"task-processor/internal/parsers/mandarake"
2025-10-03 19:17:01 +03:00
"task-processor/internal/processor"
2025-12-20 16:05:56 +03:00
"task-processor/internal/remote"
2025-10-03 19:17:01 +03:00
"task-processor/internal/shared"
2026-02-17 12:19:47 +03:00
"task-processor/pkg/router"
2025-10-02 20:35:53 +03:00
"time"
)
type App struct {
2025-10-03 19:17:01 +03:00
config *config.Config
checkPeriod time.Duration
startTime time.Time
retryCount int
retryMinutes int
state *appState.State
2025-12-20 16:05:56 +03:00
network *remote.Network
2025-10-03 19:17:01 +03:00
numCPUs int
2026-02-28 10:53:33 +03:00
metricsSrv *router.Handler
taskApiSrv *grpc.Server
2025-10-02 20:35:53 +03:00
}
func New(c *config.Config) *App {
numCPUs := c.NumCPUs
if numCPUs < 1 {
numCPUs = runtime.NumCPU()
}
2025-10-03 19:17:01 +03:00
st := appState.NewState(numCPUs, c.CheckPeriod, c.TasksCfg.RetryCount, c.TasksCfg.RetryMinutes)
2025-10-02 20:35:53 +03:00
2026-02-28 10:53:33 +03:00
server := newServer(st)
//metrics
mSrv := router.NewHandler(router.Deps{
Addr: net.JoinHostPort(c.Metrics.Host, c.Metrics.Port),
GinMode: c.Metrics.GinMode,
})
2025-10-02 20:35:53 +03:00
return &App{
2025-10-03 19:17:01 +03:00
config: c,
checkPeriod: time.Duration(c.CheckPeriod),
startTime: time.Now(),
retryCount: c.TasksCfg.RetryCount,
retryMinutes: c.TasksCfg.RetryMinutes,
state: st,
2025-12-20 16:05:56 +03:00
network: remote.NewHandler(),
2025-10-03 19:17:01 +03:00
numCPUs: numCPUs,
2026-02-28 10:53:33 +03:00
metricsSrv: mSrv,
taskApiSrv: server,
2025-10-02 20:35:53 +03:00
}
}
2026-02-28 10:53:33 +03:00
func (app *App) Run(ctx context.Context) {
2025-10-02 20:35:53 +03:00
log.Info("Application start")
2026-02-28 10:53:33 +03:00
addr := net.JoinHostPort(app.config.GrpcCfg.ServerHost, app.config.GrpcCfg.ServerPort)
2025-10-02 20:35:53 +03:00
log.WithFields(log.Fields{
2026-02-28 10:53:33 +03:00
"Service address": addr,
2025-10-03 19:17:01 +03:00
"Number of CPUs": app.numCPUs,
2025-10-02 20:35:53 +03:00
}).Debug("App settings")
2026-02-28 10:53:33 +03:00
errChan := make(chan error, 16)
2026-02-17 12:19:47 +03:00
//main
2025-10-03 19:17:01 +03:00
apiClient := newApiClient(app.config.GrpcCfg.ApiClientHost + ":" + app.config.GrpcCfg.ApiClientPort)
2025-10-02 20:35:53 +03:00
2025-10-03 19:17:01 +03:00
sender := make(chan shared.TaskResult, app.numCPUs*10)
2026-02-28 10:53:33 +03:00
defer close(sender)
2025-10-03 19:17:01 +03:00
// external scrapper
surugayaScrapper := newSurugayaScrapperClient(app.config.GrpcCfg.SurugayaScrapperHost + ":" + app.config.GrpcCfg.SurugayaScrapperPort)
2025-10-02 20:35:53 +03:00
//task processor
2025-12-26 18:49:22 +03:00
handlers := make(map[string]parsers.TaskHandler)
2025-12-26 16:19:09 +03:00
2025-12-26 18:49:22 +03:00
if app.config.OriginEnabled.Surugaya {
2026-02-28 10:53:33 +03:00
handlers[shared.OriginSurugaya] = parsers.NewSurugayaParser(surugayaScrapper)
2025-12-26 18:49:22 +03:00
}
if app.config.OriginEnabled.Mandarake {
2026-02-28 10:53:33 +03:00
handlers[shared.OriginMandarake] = mandarake.NewParser(mandarake.Deps{
2025-12-26 16:19:09 +03:00
Enabled: app.config.OriginEnabled.Mandarake,
ExternalBrowser: app.config.ExternalBrowser,
GoroutinesNumber: app.numCPUs,
2026-02-28 23:33:22 +03:00
TaskTimeout: app.config.TasksCfg.TaskTimeout,
2025-12-26 18:49:22 +03:00
})
2025-10-02 20:35:53 +03:00
}
taskProcessor := processor.New(processor.Deps{
Handlers: handlers,
Out: sender,
2025-10-03 19:17:01 +03:00
State: app.state,
2025-10-02 20:35:53 +03:00
Ctx: ctx,
2025-10-03 19:17:01 +03:00
NumCPUs: app.numCPUs,
2025-10-02 20:35:53 +03:00
})
process := func() {
2025-10-03 19:17:01 +03:00
app.state.SetStatus(appState.StatusRequestTasks)
2025-10-02 20:35:53 +03:00
log.Info("Requesting data for parsing")
2025-10-03 19:17:01 +03:00
receivedTasks := app.network.RequestTasks(ctx, apiClient)
2025-10-02 20:35:53 +03:00
log.WithField("length", len(receivedTasks)).Debug("End receiving")
2026-02-28 10:53:33 +03:00
taskProcessor.StartWork(ctx, receivedTasks)
2025-10-02 20:35:53 +03:00
}
2026-02-28 23:33:22 +03:00
period := time.NewTicker(app.checkPeriod * time.Hour)
defer period.Stop()
2025-10-02 20:35:53 +03:00
go func() {
process() //immediate start
for range period.C {
process()
}
}()
//done tasks sender
go func() {
ticker := time.NewTicker(time.Second * 2)
defer ticker.Stop()
var sendData []shared.TaskResult
for {
select {
case task := <-sender:
sendData = append(sendData, task)
case <-ticker.C:
l := len(sendData)
if l > 0 {
log.WithField("length", l).Debug("Sending parsed data")
2026-03-01 01:01:06 +03:00
app.network.SendResult(ctx, apiClient, sendData)
2025-10-02 20:35:53 +03:00
sendData = sendData[:0]
}
}
}
}()
2026-02-17 12:19:47 +03:00
//start metrics server
go func() {
2026-02-28 10:53:33 +03:00
if err := app.metricsSrv.Run(); err != nil {
errChan <- err
2026-02-17 12:19:47 +03:00
}
}()
2025-10-02 20:35:53 +03:00
//gRPC Server for status response
go func() {
2026-02-28 10:53:33 +03:00
listener, err := net.Listen("tcp", addr)
2025-10-02 20:35:53 +03:00
if err != nil {
2026-02-28 10:53:33 +03:00
errChan <- err
2025-10-02 20:35:53 +03:00
}
2026-02-28 10:53:33 +03:00
log.Infof("gRPC Server listening at %v", addr)
if err = app.taskApiSrv.Serve(listener); err != nil {
errChan <- err
2025-10-02 20:35:53 +03:00
}
}()
2026-02-28 10:53:33 +03:00
select {
case <-ctx.Done():
app.shutdown(ctx)
case err := <-errChan:
log.WithError(err).Fatal("Application run error")
}
}
func (app *App) shutdown(ctx context.Context) {
log.Info("Shutting down...")
2026-02-17 12:19:47 +03:00
2026-02-28 10:53:33 +03:00
app.taskApiSrv.GracefulStop()
if err := app.metricsSrv.Shutdown(ctx); err != nil {
log.WithError(err).Error("Failed to shutdown server")
}
2025-10-02 20:35:53 +03:00
}