package themis import ( "context" "fmt" "time" "github.com/rs/zerolog/log" "go.opentelemetry.io/otel/trace" ) var loc *time.Location func init() { loc, _ = time.LoadLocation("America/New_York") } type Notifier struct { c chan context.Context } func NewNotifier(c chan context.Context) *Notifier { return &Notifier{ c: c, } } func (n *Notifier) Start(ctx context.Context) { m := NextMonday() sat := m.AddDate(0, 0, -2) if sat.Before(time.Now()) { sat = sat.AddDate(0, 0, 7) } t, err := time.ParseInLocation(time.DateTime, fmt.Sprintf("%s 17:00:00", sat.Format(time.DateOnly)), loc) if err != nil { panic("failed to parse next monday notif time. this is likely a bug.") } log.Debug().Time("next", t).Msg("starting notifier instance") first := time.NewTimer(time.Until(t)) <-first.C select { case <-ctx.Done(): log.Debug().Msg("context deadline exceeded, exiting notifier") return default: log.Debug().Str("parent", "ticker").Msg("notifier tick") ctx, span := tracer.Start(ctx, "notifier_tick", trace.WithNewRoot()) n.c <- ctx span.End() } ticker := time.NewTicker(time.Hour * 24 * 7) for { select { case <-ctx.Done(): log.Debug().Msg("context deadline exceeded, exiting notifier") return case <-ticker.C: log.Debug().Str("parent", "ticker").Msg("notifier tick") ctx, span := tracer.Start(ctx, "notifier_tick", trace.WithNewRoot()) n.c <- ctx span.End() } time.Sleep(time.Second) } } // Trigger the notifier manually. Should be used for testing purposes only. func (n *Notifier) Send(ctx context.Context) { log.Debug().Str("parent", "trigger").Ctx(ctx).Msg("notifier tick") n.c <- ctx } // TODO(wperron) is there a (nice) way to instrument this function? func (n *Notifier) NotifyFunc(ctx context.Context, f func(context.Context)) { for { select { case <-ctx.Done(): log.Debug().Msg("context deadline exceeded, exiting notify func") return case innerCtx := <-n.c: log.Debug().Ctx(innerCtx).Msg("tick received, notifying function") f(innerCtx) } time.Sleep(time.Second) } }