132 lines
3.1 KiB
Go
132 lines
3.1 KiB
Go
package ports
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log/slog"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.loyso.art/frx/kurious/internal/common/client/sravni"
|
|
"git.loyso.art/frx/kurious/internal/common/errors"
|
|
"git.loyso.art/frx/kurious/internal/common/nullable"
|
|
"git.loyso.art/frx/kurious/internal/common/xcontext"
|
|
"git.loyso.art/frx/kurious/internal/common/xlog"
|
|
"git.loyso.art/frx/kurious/internal/kurious/ports/background"
|
|
"git.loyso.art/frx/kurious/internal/kurious/service"
|
|
|
|
"github.com/robfig/cron/v3"
|
|
)
|
|
|
|
type BackgroundProcess struct {
|
|
scheduler *cron.Cron
|
|
log *slog.Logger
|
|
|
|
syncSravniHandlerEntryID nullable.Value[cron.EntryID]
|
|
syncSravniHandler handler
|
|
}
|
|
|
|
func NewBackgroundProcess(ctx context.Context, log *slog.Logger) *BackgroundProcess {
|
|
clog := xlog.WrapSLogger(ctx, log)
|
|
scheduler := cron.New(
|
|
cron.WithSeconds(),
|
|
cron.WithChain(
|
|
cron.Recover(clog),
|
|
),
|
|
)
|
|
|
|
bp := &BackgroundProcess{
|
|
scheduler: scheduler,
|
|
log: log,
|
|
}
|
|
|
|
return bp
|
|
}
|
|
|
|
func (bp *BackgroundProcess) RegisterSyncSravniHandler(
|
|
ctx context.Context,
|
|
svc service.Application,
|
|
client sravni.Client,
|
|
cronValue string,
|
|
) (err error) {
|
|
const handlerName = "sync_sravni_handler"
|
|
|
|
bp.syncSravniHandler = background.NewSyncSravniHandler(svc, client, bp.log)
|
|
|
|
if cronValue == "" {
|
|
return nil
|
|
}
|
|
bp.syncSravniHandlerEntryID, err = bp.registerHandler(ctx, cronValue, handlerName, bp.syncSravniHandler)
|
|
return err
|
|
}
|
|
|
|
func (bp *BackgroundProcess) ForceExecuteSyncSravniHandler(ctx context.Context) error {
|
|
if bp.syncSravniHandler == nil {
|
|
return errors.SimpleError("sync sravni handler not mounted")
|
|
}
|
|
return bp.syncSravniHandler.Handle(ctx)
|
|
}
|
|
|
|
type NextRunStats map[string]time.Time
|
|
|
|
func (s NextRunStats) String() string {
|
|
var sb strings.Builder
|
|
_ = json.NewEncoder(&sb).Encode(s)
|
|
return sb.String()
|
|
}
|
|
|
|
func (bp *BackgroundProcess) GetNextRunStats() NextRunStats {
|
|
out := make(NextRunStats)
|
|
if bp.syncSravniHandlerEntryID.Valid() {
|
|
entryID := bp.syncSravniHandlerEntryID.Value()
|
|
sEntry := bp.scheduler.Entry(entryID)
|
|
out["sravni_handler"] = sEntry.Next
|
|
}
|
|
|
|
return NextRunStats(out)
|
|
}
|
|
|
|
func (bp *BackgroundProcess) Run() {
|
|
bp.scheduler.Run()
|
|
}
|
|
|
|
func (bp *BackgroundProcess) Shutdown(ctx context.Context) error {
|
|
sdctx := bp.scheduler.Stop()
|
|
|
|
select {
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
case <-sdctx.Done():
|
|
return nil
|
|
}
|
|
}
|
|
|
|
type handler interface {
|
|
Handle(context.Context) error
|
|
}
|
|
|
|
func (bp *BackgroundProcess) registerHandler(ctx context.Context, spec, name string, h handler) (nullable.Value[cron.EntryID], error) {
|
|
handlerField := slog.String("handler", name)
|
|
jctx := xcontext.WithLogFields(ctx, handlerField)
|
|
|
|
xcontext.LogInfo(jctx, bp.log, "registering handler", handlerField)
|
|
|
|
entry, err := bp.scheduler.AddJob(spec, cron.FuncJob(func() {
|
|
err := h.Handle(jctx)
|
|
if err != nil {
|
|
xcontext.LogWithError(jctx, bp.log, err, "unable to run iteration")
|
|
}
|
|
xcontext.LogInfo(jctx, bp.log, "iteration completed")
|
|
}))
|
|
|
|
if err != nil {
|
|
return nullable.Value[cron.EntryID]{}, fmt.Errorf("adding %s job: %w", name, err)
|
|
}
|
|
|
|
var out nullable.Value[cron.EntryID]
|
|
out.Set(entry)
|
|
|
|
return out, nil
|
|
}
|