Yimaru-BackEnd/internal/web_server/cron.go
Samuel Tariku e49ff366d5 feat: Implement wallet notification system and refactor related services
- Added new notification handling in the wallet service to notify admins when wallet balances are low or insufficient.
- Created a new file for wallet notifications and moved relevant functions from the wallet service to this new file.
- Updated the wallet service to publish wallet events including wallet type.
- Refactored the client code to improve readability and maintainability.
- Enhanced the bet handler to support pagination and status filtering for bets.
- Updated routes and handlers for user search functionality to improve clarity and organization.
- Modified cron job scheduling to comment out unused jobs for clarity.
- Updated the WebSocket broadcast to include wallet type in notifications.
- Adjusted the makefile to include Kafka in the docker-compose setup for local development.
2025-09-25 21:26:24 +03:00

245 lines
7.1 KiB
Go

package httpserver
import (
"context"
"os"
"time"
"log"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
betSvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
eventsvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
oddssvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/report"
resultsvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/result"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/ticket"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/veli"
"github.com/robfig/cron/v3"
"go.uber.org/zap"
)
func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.ServiceImpl, resultService *resultsvc.Service, mongoLogger *zap.Logger) {
c := cron.New(cron.WithSeconds())
schedule := []struct {
spec string
task func()
}{
// {
// spec: "0 0 * * * *", // Every 1 hour
// task: func() {
// mongoLogger.Info("Began fetching upcoming events cron task")
// if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
// mongoLogger.Error("Failed to fetch upcoming events",
// zap.Error(err),
// )
// } else {
// mongoLogger.Info("Completed fetching upcoming events without errors")
// }
// },
// },
// {
// spec: "0 0 * * * *", // Every 1 hour (since its takes that long to fetch all the events)
// task: func() {
// mongoLogger.Info("Began fetching non live odds cron task")
// if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
// mongoLogger.Error("Failed to fetch non live odds",
// zap.Error(err),
// )
// } else {
// mongoLogger.Info("Completed fetching non live odds without errors")
// }
// },
// },
// {
// spec: "0 */5 * * * *", // Every 5 Minutes
// task: func() {
// mongoLogger.Info("Began update all expired events status cron task")
// if _, err := resultService.CheckAndUpdateExpiredB365Events(context.Background()); err != nil {
// mongoLogger.Error("Failed to update expired events status",
// zap.Error(err),
// )
// } else {
// mongoLogger.Info("Completed expired events without errors")
// }
// },
// },
// {
// spec: "0 */15 * * * *", // Every 15 Minutes
// task: func() {
// mongoLogger.Info("Began updating bets based on event results cron task")
// if err := resultService.FetchB365ResultAndUpdateBets(context.Background()); err != nil {
// mongoLogger.Error("Failed to process result",
// zap.Error(err),
// )
// } else {
// mongoLogger.Info("Completed processing all event result outcomes without errors")
// }
// },
// },
// {
// spec: "0 0 0 * * 1", // Every Monday
// task: func() {
// mongoLogger.Info("Began Send weekly result notification cron task")
// if err := resultService.CheckAndSendResultNotifications(context.Background(), time.Now().Add(-7*24*time.Hour)); err != nil {
// mongoLogger.Error("Failed to process result",
// zap.Error(err),
// )
// } else {
// mongoLogger.Info("Completed sending weekly result notification without errors")
// }
// },
// },
}
for _, job := range schedule {
// job.task()
if _, err := c.AddFunc(job.spec, job.task); err != nil {
mongoLogger.Error("Failed to schedule data fetching cron job",
zap.Error(err),
)
}
}
c.Start()
log.Println("Cron jobs started for event and odds services")
mongoLogger.Info("Cron jobs started for event and odds services")
}
func StartTicketCrons(ticketService ticket.Service, mongoLogger *zap.Logger) {
c := cron.New(cron.WithSeconds())
schedule := []struct {
spec string
task func()
}{
{
spec: "0 0 * * * *", // Every hour
task: func() {
mongoLogger.Info("Deleting old tickets")
if err := ticketService.DeleteOldTickets(context.Background()); err != nil {
mongoLogger.Error("Failed to remove old ticket",
zap.Error(err),
)
} else {
mongoLogger.Info("Successfully deleted old tickets")
}
},
},
}
for _, job := range schedule {
if _, err := c.AddFunc(job.spec, job.task); err != nil {
mongoLogger.Error("Failed to schedule ticket cron job",
zap.Error(err),
)
}
}
c.Start()
mongoLogger.Info("Cron jobs started for ticket service")
}
// SetupReportCronJobs schedules periodic report generation
func SetupReportandVirtualGameCronJobs(
ctx context.Context,
reportService *report.Service,
virtualGameService *veli.Service, // inject your virtual game service
outputDir string,
) {
c := cron.New(cron.WithSeconds()) // use WithSeconds for testing
schedule := []struct {
spec string
period string
}{
// {
// spec: "*/60 * * * * *", // Every 1 minute for testing
// period: "test",
// },
{
spec: "0 0 0 * * *", // Daily at midnight
period: "daily",
},
}
for _, job := range schedule {
period := job.period
if _, err := c.AddFunc(job.spec, func() {
log.Printf("[%s] Running virtual game fetch & store job...", period)
brandID := os.Getenv("VELI_BRAND_ID")
if brandID == "" {
log.Println("VELI_BRAND_ID not set, skipping virtual game sync")
return
}
req := domain.ProviderRequest{
BrandID: brandID,
ExtraData: true,
Size: 1000,
Page: 1,
}
allGames, err := virtualGameService.FetchAndStoreAllVirtualGames(ctx, req, "ETB")
if err != nil {
log.Printf("[%s] Error fetching/storing virtual games: %v", period, err)
return
}
log.Printf("[%s] Successfully fetched & stored %d virtual games", period, len(allGames))
// --- Generate reports only for daily runs ---
if period == "daily" {
now := time.Now()
from := time.Date(now.Year(), now.Month(), now.Day()-1, 0, 0, 0, 0, now.Location())
to := time.Date(now.Year(), now.Month(), now.Day()-1, 23, 59, 59, 0, now.Location())
log.Printf("Running daily report for period %s -> %s", from.Format(time.RFC3339), to.Format(time.RFC3339))
if err := reportService.GenerateReport(ctx, from, to); err != nil {
log.Printf("Error generating daily report: %v", err)
} else {
log.Printf("Successfully generated daily report")
}
}
}); err != nil {
log.Fatalf("Failed to schedule %s cron job: %v", period, err)
}
}
c.Start()
log.Printf("Cron jobs started. Reports will be saved to: %s", outputDir)
}
func ProcessBetCashback(ctx context.Context, betService *betSvc.Service) {
c := cron.New(cron.WithSeconds())
schedule := []struct {
spec string
task func()
}{
{
spec: "0 0 0 * * *", // Daily at midnight
task: func() {
log.Println("process bet cashbacks...")
if err := betService.ProcessBetCashback(ctx); err != nil {
log.Printf("Failed to process bet cashbacks: %v", err)
} else {
log.Printf("Successfully processed bet cashbacks")
}
},
},
}
for _, job := range schedule {
if _, err := c.AddFunc(job.spec, job.task); err != nil {
log.Fatalf("Failed to schedule cron job: %v", err)
}
}
c.Start()
log.Println("Cron jobs started for bet cashbacks")
}