60 lines
2.2 KiB
Go
60 lines
2.2 KiB
Go
// Package scheduler exposes the next-tick computation Game Master uses
|
|
// to advance `runtime_records.next_generation_at` after a successful
|
|
// turn generation. It is a thin, stateless wrapper over
|
|
// `domain/schedule.Schedule.Next` with the force-next-turn skip rule
|
|
// baked in via the `skipNextTick` parameter.
|
|
//
|
|
// Two callers consume the wrapper today:
|
|
//
|
|
// - `service/turngeneration` recomputes the next tick after a
|
|
// successful (non-finished) generation;
|
|
// - `service/adminforce` (Stage 17) reuses the same instance so the
|
|
// skip rule lives in exactly one place.
|
|
//
|
|
// The package depends only on `domain/schedule` and stdlib `time`. It
|
|
// holds no clock and no logger; callers pass `after` explicitly.
|
|
package scheduler
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"time"
|
|
|
|
"galaxy/gamemaster/internal/domain/schedule"
|
|
)
|
|
|
|
// Service computes the next scheduler-driven turn-generation tick.
|
|
type Service struct{}
|
|
|
|
// New constructs a stateless Service value. Returning a pointer keeps
|
|
// the construction shape consistent with the other GM services even
|
|
// though Service has no dependencies.
|
|
func New() *Service {
|
|
return &Service{}
|
|
}
|
|
|
|
// ComputeNext parses turnSchedule and returns the next firing time
|
|
// strictly after `after`, applying the force-next-turn skip rule when
|
|
// skipNextTick is true.
|
|
//
|
|
// When skipNextTick is true the wrapper computes the immediate next
|
|
// cron step and then advances by one further step, so the inter-turn
|
|
// spacing is never shorter than one schedule interval. The returned
|
|
// `skipConsumed` flag reports whether the wrapper consumed the skip
|
|
// (true when skipNextTick was true).
|
|
//
|
|
// On parse error ComputeNext returns the zero time, false, and the
|
|
// error wrapped from `schedule.Parse`. The caller is responsible for
|
|
// mapping it to the orchestrator-level `invalid_request` code.
|
|
func (service *Service) ComputeNext(turnSchedule string, after time.Time, skipNextTick bool) (time.Time, bool, error) {
|
|
if service == nil {
|
|
return time.Time{}, false, errors.New("scheduler compute next: nil service")
|
|
}
|
|
parsed, err := schedule.Parse(strings.TrimSpace(turnSchedule))
|
|
if err != nil {
|
|
return time.Time{}, false, err
|
|
}
|
|
next, skipConsumed := parsed.Next(after, skipNextTick)
|
|
return next, skipConsumed, nil
|
|
}
|