Add round-robin posting mode
One story per interval_hours (default 4), cycling through enabled sources in config order. Empty sources are skipped and the pointer advances to whichever source actually posted. State persists across restarts. Duplicate-flagged stories now get a _duplicate sentinel channel so they stay out of the rotation pool alongside _discarded.
This commit is contained in:
26
main.go
26
main.go
@@ -15,6 +15,7 @@ import (
|
||||
"pete/internal/ingestion"
|
||||
"pete/internal/matrix"
|
||||
"pete/internal/poster"
|
||||
"pete/internal/scheduler"
|
||||
"pete/internal/storage"
|
||||
)
|
||||
|
||||
@@ -94,7 +95,10 @@ func main() {
|
||||
go queue.Start(ctx)
|
||||
slog.Info("post queue started")
|
||||
|
||||
// Build the pipeline callback: classify → enqueue
|
||||
roundRobinMode := cfg.Posting.RoundRobin.Enabled
|
||||
|
||||
// Build the pipeline callback: classify → enqueue (or just classify+store
|
||||
// when round-robin mode is enabled; the scheduler does the enqueueing).
|
||||
processItem := func(ctx context.Context, item *ingestion.FeedItem) {
|
||||
result, err := cls.Classify(ctx, item)
|
||||
if err != nil {
|
||||
@@ -123,6 +127,9 @@ func main() {
|
||||
storage.MarkClassified(item.GUID, result.Channel, platforms)
|
||||
|
||||
if result.DuplicateOf != nil {
|
||||
// Overwrite with sentinel so the round-robin scheduler doesn't pick
|
||||
// this up later. Immediate-mode posting already returned above.
|
||||
storage.MarkClassified(item.GUID, "_duplicate", "[]")
|
||||
slog.Info("story deduplicated",
|
||||
"guid", item.GUID,
|
||||
"duplicate_of", *result.DuplicateOf,
|
||||
@@ -130,6 +137,14 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
if roundRobinMode {
|
||||
// Story stays in DB classified+postable; the scheduler will pick
|
||||
// it up on the next rotation tick.
|
||||
slog.Info("story classified, awaiting round-robin tick",
|
||||
"guid", item.GUID, "source", item.Source, "channel", result.Channel)
|
||||
return
|
||||
}
|
||||
|
||||
// Validate image
|
||||
imageURL := ""
|
||||
if item.ImageURL != "" && ingestion.ValidateImageURL(item.ImageURL) {
|
||||
@@ -154,6 +169,15 @@ func main() {
|
||||
poller.Start(ctx)
|
||||
slog.Info("pollers started")
|
||||
|
||||
if roundRobinMode {
|
||||
rr := scheduler.New(cfg.Sources, cfg.Posting.RoundRobin.IntervalHours, queue)
|
||||
if rr == nil {
|
||||
slog.Warn("round-robin enabled but no sources are enabled; nothing will post")
|
||||
} else {
|
||||
go rr.Start(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// Run maintenance on startup
|
||||
storage.RunMaintenance(cfg.Storage.RecentWindowHours, cfg.Storage.ClassificationLogDays)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user