Add cron job functionality and Docker integration

This commit is contained in:
2026-01-31 00:31:43 +03:00
parent 73acc5410f
commit ad12844992
6 changed files with 210 additions and 30 deletions

View File

@@ -327,40 +327,57 @@ go run ./cmd/server
# Run importer (one-time setup)
go run ./cmd/importer
# Run cron jobs manually
go run ./cmd/cron -job=alerts # Check and generate alerts
go run ./cmd/cron -job=update-prices # Recalculate all prices
go run ./cmd/cron -job=reset-counters # Reset usage counters
go run ./cmd/cron -job=update-popularity # Update popularity scores
# Build for production
CGO_ENABLED=0 go build -ldflags="-s -w" -o bin/quoteforge ./cmd/server
CGO_ENABLED=0 go build -ldflags="-s -w" -o bin/quoteforge-cron ./cmd/cron
# Run tests
go test ./...
````
## Cron Jobs
QuoteForge now includes automated cron jobs for maintenance tasks. These can be run using the built-in cron functionality in the Docker container.
### Docker Compose Setup
The Docker setup includes a dedicated cron service that runs the following jobs:
- **Alerts check**: Every hour (0 * * * *)
- **Price updates**: Daily at 2 AM (0 2 * * *)
- **Usage counter reset**: Weekly on Sunday at 1 AM (0 1 * * 0)
- **Popularity score updates**: Daily at 3 AM (0 3 * * *)
### Manual Cron Job Execution
You can also run cron jobs manually using the quoteforge-cron binary:
```bash
# Check and generate alerts
go run ./cmd/cron -job=alerts
# Recalculate all prices
go run ./cmd/cron -job=update-prices
# Reset usage counters
go run ./cmd/cron -job=reset-counters
# Update popularity scores
go run ./cmd/cron -job=update-popularity
```
## Dependencies (go.mod)
### Cron Job Details
```go
module git.mchus.pro/mchus/quoteforge
go 1.22
require (
github.com/gin-gonic/gin v1.9.1
github.com/go-sql-driver/mysql v1.7.1
gorm.io/gorm v1.25.5
gorm.io/driver/mysql v1.5.2
github.com/xuri/excelize/v2 v2.8.0
github.com/golang-jwt/jwt/v5 v5.2.0
github.com/google/uuid v1.5.0
golang.org/x/crypto v0.17.0
gopkg.in/yaml.v3 v3.0.1
)
```
## Development Priorities
1. **Phase 1 (MVP):** Project setup, models, component API, basic UI, CSV export
2. **Phase 2:** JWT auth with roles, pricing admin UI, all price methods
3. **Phase 3:** Save/load configs, JSON import/export, XLSX export, cron jobs
4. **Phase 4:** Usage stats, alerts system, dashboard
5. **Phase 5:** Polish, tests, Docker, documentation
- **Alerts check**: Generates alerts for components with high demand and stale prices, trending components without prices, and components with no recent quotes
- **Price updates**: Recalculates prices for all components using configured methods (median, weighted median, average)
- **Usage counter reset**: Resets weekly and monthly usage counters for components
- **Popularity score updates**: Recalculates popularity scores based on supplier quote activity
## Code Style

View File

@@ -12,16 +12,22 @@ RUN go mod download
# Copy source code
COPY . .
# Build the binary
# Build the main binary
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
-ldflags="-s -w" \
-o /app/quoteforge \
./cmd/server
# Build the cron binary
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
-ldflags="-s -w" \
-o /app/quoteforge-cron \
./cmd/cron
# Final stage
FROM alpine:3.19
RUN apk add --no-cache ca-certificates tzdata
RUN apk add --no-cache ca-certificates tzdata cron
# Create non-root user
RUN adduser -D -g '' appuser
@@ -30,6 +36,14 @@ WORKDIR /app
# Copy binary from builder
COPY --from=builder /app/quoteforge .
COPY --from=builder /app/quoteforge-cron .
# Copy cron job configuration
COPY crontab /etc/crontabs/appuser
RUN chmod 0600 /etc/crontabs/appuser
# Create log directory
RUN mkdir -p /var/log/cron
# Copy web templates and static files
COPY --from=builder /app/web ./web

View File

@@ -163,12 +163,48 @@ GET /api/configs # Сохранённые конфигурации
## Cron Jobs
Система автоматического обновления цен не реализована в текущей версии. Для обновления цен можно использовать команду:
QuoteForge now includes automated cron jobs for maintenance tasks. These can be run using the built-in cron functionality in the Docker container.
### Docker Compose Setup
The Docker setup includes a dedicated cron service that runs the following jobs:
- **Alerts check**: Every hour (0 * * * *)
- **Price updates**: Daily at 2 AM (0 2 * * *)
- **Usage counter reset**: Weekly on Sunday at 1 AM (0 1 * * 0)
- **Popularity score updates**: Daily at 3 AM (0 3 * * *)
To enable cron jobs in Docker, run:
```bash
go run ./cmd/server -migrate
docker-compose up -d
```
### Manual Cron Job Execution
You can also run cron jobs manually using the quoteforge-cron binary:
```bash
# Check and generate alerts
go run ./cmd/cron -job=alerts
# Recalculate all prices
go run ./cmd/cron -job=update-prices
# Reset usage counters
go run ./cmd/cron -job=reset-counters
# Update popularity scores
go run ./cmd/cron -job=update-popularity
```
### Cron Job Details
- **Alerts check**: Generates alerts for components with high demand and stale prices, trending components without prices, and components with no recent quotes
- **Price updates**: Recalculates prices for all components using configured methods (median, weighted median, average)
- **Usage counter reset**: Resets weekly and monthly usage counters for components
- **Popularity score updates**: Recalculates popularity scores based on supplier quote activity
## Разработка
```bash

85
cmd/cron/main.go Normal file
View File

@@ -0,0 +1,85 @@
package main
import (
"flag"
"log"
"time"
"git.mchus.pro/mchus/quoteforge/internal/config"
"git.mchus.pro/mchus/quoteforge/internal/models"
"git.mchus.pro/mchus/quoteforge/internal/repository"
"git.mchus.pro/mchus/quoteforge/internal/services/alerts"
"git.mchus.pro/mchus/quoteforge/internal/services/pricing"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
func main() {
configPath := flag.String("config", "config.yaml", "path to config file")
cronJob := flag.String("job", "", "type of cron job to run (alerts, update-prices)")
flag.Parse()
cfg, err := config.Load(*configPath)
if err != nil {
log.Fatalf("Failed to load config: %v", err)
}
db, err := gorm.Open(mysql.Open(cfg.Database.DSN()), &gorm.Config{
Logger: logger.Default.LogMode(logger.Silent),
})
if err != nil {
log.Fatalf("Failed to connect to database: %v", err)
}
// Ensure tables exist
if err := models.Migrate(db); err != nil {
log.Fatalf("Migration failed: %v", err)
}
// Initialize repositories
statsRepo := repository.NewStatsRepository(db)
alertRepo := repository.NewAlertRepository(db)
componentRepo := repository.NewComponentRepository(db)
priceRepo := repository.NewPriceRepository(db)
// Initialize services
alertService := alerts.NewService(alertRepo, componentRepo, priceRepo, statsRepo, cfg.Alerts, cfg.Pricing)
pricingService := pricing.NewService(componentRepo, priceRepo, cfg.Pricing)
switch *cronJob {
case "alerts":
log.Println("Running alerts check...")
if err := alertService.CheckAndGenerateAlerts(); err != nil {
log.Printf("Error running alerts check: %v", err)
} else {
log.Println("Alerts check completed successfully")
}
case "update-prices":
log.Println("Recalculating all prices...")
updated, errors := pricingService.RecalculateAllPrices()
log.Printf("Prices recalculated: %d updated, %d errors", updated, errors)
case "reset-counters":
log.Println("Resetting usage counters...")
if err := statsRepo.ResetWeeklyCounters(); err != nil {
log.Printf("Error resetting weekly counters: %v", err)
}
if err := statsRepo.ResetMonthlyCounters(); err != nil {
log.Printf("Error resetting monthly counters: %v", err)
}
log.Println("Usage counters reset completed")
case "update-popularity":
log.Println("Updating popularity scores...")
if err := statsRepo.UpdatePopularityScores(); err != nil {
log.Printf("Error updating popularity scores: %v", err)
} else {
log.Println("Popularity scores updated successfully")
}
default:
log.Println("No valid cron job specified. Available jobs:")
log.Println(" - alerts: Check and generate alerts")
log.Println(" - update-prices: Recalculate all prices")
log.Println(" - reset-counters: Reset usage counters")
log.Println(" - update-popularity: Update popularity scores")
}
}

15
crontab Normal file
View File

@@ -0,0 +1,15 @@
# Cron jobs for QuoteForge
# Run alerts check every hour
0 * * * * /app/quoteforge-cron -job=alerts
# Run price updates daily at 2 AM
0 2 * * * /app/quoteforge-cron -job=update-prices
# Reset weekly counters every Sunday at 1 AM
0 1 * * 0 /app/quoteforge-cron -job=reset-counters
# Update popularity scores daily at 3 AM
0 3 * * * /app/quoteforge-cron -job=update-popularity
# Log rotation (optional)
# 0 0 * * * /usr/bin/logrotate /etc/logrotate.conf

View File

@@ -1,3 +1,5 @@
version: '3.8'
services:
quoteforge:
build: .
@@ -15,3 +17,14 @@ services:
timeout: 3s
retries: 3
start_period: 5s
quoteforge-cron:
build: .
container_name: quoteforge-cron
restart: unless-stopped
volumes:
- ./config.yaml:/app/config.yaml:ro
- ./logs:/app/logs
command: /usr/sbin/crond -f -l 8
environment:
- TZ=Europe/Moscow