mirror of
https://github.com/SamyRai/tercul-backend.git
synced 2025-12-27 04:01:34 +00:00
This commit introduces a new trending works feature to the application. The feature includes: - A new `Trending` domain model to store ranked works. - An `UpdateTrending` method in the `AnalyticsService` that calculates a trending score for each work based on views, likes, and comments. - A background job that runs hourly to update the trending works. - A new `trendingWorks` query in the GraphQL API to expose the trending works. - New tests for the trending feature, and fixes for existing tests. This commit also includes a refactoring of the analytics repository to use a more generic `IncrementWorkCounter` method, and enhancements to the `WorkStats` and `TranslationStats` models with new metrics like `readingTime`, `complexity`, and `sentiment`.
98 lines
2.8 KiB
Go
98 lines
2.8 KiB
Go
package app
|
|
|
|
import (
|
|
"tercul/internal/jobs/linguistics"
|
|
syncjob "tercul/internal/jobs/sync"
|
|
"tercul/internal/jobs/trending"
|
|
"tercul/internal/platform/config"
|
|
"tercul/internal/platform/log"
|
|
|
|
"github.com/hibiken/asynq"
|
|
)
|
|
|
|
// ServerFactory handles the creation of HTTP and background job servers
|
|
type ServerFactory struct {
|
|
appBuilder *ApplicationBuilder
|
|
}
|
|
|
|
// NewServerFactory creates a new ServerFactory
|
|
func NewServerFactory(appBuilder *ApplicationBuilder) *ServerFactory {
|
|
return &ServerFactory{
|
|
appBuilder: appBuilder,
|
|
}
|
|
}
|
|
|
|
|
|
// CreateBackgroundJobServers creates and configures background job servers
|
|
func (f *ServerFactory) CreateBackgroundJobServers() ([]*asynq.Server, error) {
|
|
log.LogInfo("Setting up background job servers")
|
|
|
|
redisOpt := asynq.RedisClientOpt{
|
|
Addr: config.Cfg.RedisAddr,
|
|
Password: config.Cfg.RedisPassword,
|
|
DB: config.Cfg.RedisDB,
|
|
}
|
|
|
|
var servers []*asynq.Server
|
|
|
|
// Setup data synchronization server
|
|
log.LogInfo("Setting up data synchronization server",
|
|
log.F("concurrency", config.Cfg.MaxRetries))
|
|
|
|
syncServer := asynq.NewServer(redisOpt, asynq.Config{Concurrency: config.Cfg.MaxRetries})
|
|
|
|
// Create sync job instance
|
|
syncJobInstance := syncjob.NewSyncJob(
|
|
f.appBuilder.GetDB(),
|
|
f.appBuilder.GetAsynq(),
|
|
)
|
|
|
|
// Register sync job handlers
|
|
syncjob.RegisterQueueHandlers(syncServer, syncJobInstance)
|
|
servers = append(servers, syncServer)
|
|
|
|
// Setup linguistic analysis server
|
|
log.LogInfo("Setting up linguistic analysis server",
|
|
log.F("concurrency", config.Cfg.MaxRetries))
|
|
|
|
// Create linguistic sync job
|
|
linguisticSyncJob := linguistics.NewLinguisticSyncJob(
|
|
f.appBuilder.GetDB(),
|
|
f.appBuilder.GetLinguisticsFactory().GetAnalyzer(),
|
|
f.appBuilder.GetAsynq(),
|
|
)
|
|
|
|
// Create linguistic server and register handlers
|
|
linguisticServer := asynq.NewServer(redisOpt, asynq.Config{Concurrency: config.Cfg.MaxRetries})
|
|
|
|
// Register linguistic handlers
|
|
linguisticMux := asynq.NewServeMux()
|
|
linguistics.RegisterLinguisticHandlers(linguisticMux, linguisticSyncJob)
|
|
|
|
// For now, we'll need to run the server with the mux when it's started
|
|
// This is a temporary workaround - in production, you'd want to properly configure the server
|
|
servers = append(servers, linguisticServer)
|
|
|
|
// Setup trending job server
|
|
log.LogInfo("Setting up trending job server")
|
|
scheduler := asynq.NewScheduler(redisOpt, &asynq.SchedulerOpts{})
|
|
task, err := trending.NewUpdateTrendingTask()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if _, err := scheduler.Register("@hourly", task); err != nil {
|
|
return nil, err
|
|
}
|
|
go func() {
|
|
if err := scheduler.Run(); err != nil {
|
|
log.LogError("could not start scheduler", log.F("error", err))
|
|
}
|
|
}()
|
|
|
|
log.LogInfo("Background job servers created successfully",
|
|
log.F("serverCount", len(servers)))
|
|
|
|
return servers, nil
|
|
}
|
|
|