mirror of
https://github.com/warmbly/warmbly.git
synced 2026-08-19 16:01:16 +00:00
7e02bb2a5a
New background job in the consumer process:
1. Pulls up to 1000 mailbox candidates joined with their worst warmup
health state (across all pools they participate in) and their
current worker's risk_pool. Dedicated workers are excluded — single
tenant, segregation not applicable.
2. Recomputes risk_band from health state via RiskBandFromHealth.
If it changed, writes the new band.
3. If the band's matching pool doesn't equal the worker's pool, picks
a new worker via SelectSharedWorkerForBand and migrates the mailbox.
Increments/decrements account counts.
4. Logs each migration to admin_audit_log with action=
"risk_rebalance_migrate" so operators see what moved and why.
Boot-time run + hourly ticker. Rebalancing is intentionally batch, not
event-driven: warmup health states change on a slow rolling-window basis
(warmup_health_sweep is also hourly), so reacting in real time gains
nothing and would cause thundering-herd migrations.
JobsService gets an AssignmentService dep. Nil disables the job (lets
self-hosters opt out by simply not wiring it).
53 lines
1.9 KiB
Go
53 lines
1.9 KiB
Go
package jobs
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/warmbly/warmbly/internal/app/advanced"
|
|
warmupapp "github.com/warmbly/warmbly/internal/app/warmup"
|
|
workerapp "github.com/warmbly/warmbly/internal/app/worker"
|
|
"github.com/warmbly/warmbly/internal/events"
|
|
"github.com/warmbly/warmbly/internal/infrastructure/cache"
|
|
"github.com/warmbly/warmbly/internal/infrastructure/kafka"
|
|
"github.com/warmbly/warmbly/internal/infrastructure/pubsub"
|
|
"github.com/warmbly/warmbly/internal/models"
|
|
"github.com/warmbly/warmbly/internal/repository"
|
|
)
|
|
|
|
type JobsService struct {
|
|
Consumer *kafka.Consumer
|
|
UniboxRepository repository.UniboxRepository
|
|
MailboxRepository repository.MailboxRepository
|
|
EmailRepository repository.EmailRepository
|
|
EmailHistoryIDRepository repository.EmailHistoryIDRepository
|
|
EmailAccountErrorRepository repository.EmailAccountErrorRepository
|
|
WarmupRepo repository.WarmupRepository
|
|
WarmupService warmupapp.Service
|
|
WorkerRepo repository.WorkerRepository
|
|
|
|
// Publisher for sending events to workers
|
|
Publisher events.Publisher
|
|
|
|
// Pub/Sub for real-time notifications to users
|
|
StreamingPublisher *pubsub.StreamingPublisher
|
|
AdvancedService advanced.Service
|
|
|
|
// Cache for dead worker detection
|
|
Cache *cache.Cache
|
|
|
|
// AdminRepo for writing audit-log rows when the dead-worker job
|
|
// auto-reassigns email accounts (optional — heartbeat sync also writes
|
|
// here so admins can see why their fleet moved). Nil disables logging.
|
|
AdminRepo repository.AdminRepository
|
|
|
|
// AssignmentService is used by the risk rebalancer to pick replacement
|
|
// workers when a mailbox's risk band changes. Nil disables the job.
|
|
AssignmentService workerapp.WorkerAssignmentService
|
|
|
|
eventHandlers map[models.JobEventType]func(ctx context.Context, body any) error
|
|
}
|
|
|
|
func (s *JobsService) Start(ctx context.Context) {
|
|
s.Consumer.Consume(ctx, s.Receive)
|
|
}
|