| 127 | } |
| 128 | |
| 129 | func (c *Checker) start() { |
| 130 | defer close(c.closed) |
| 131 | |
| 132 | r, err := c.init() |
| 133 | if err != nil { |
| 134 | if xerrors.Is(err, context.Canceled) { |
| 135 | return |
| 136 | } |
| 137 | c.log.Error(c.ctx, "init failed", slog.Error(err)) |
| 138 | } else { |
| 139 | c.opts.Notify(r) |
| 140 | } |
| 141 | |
| 142 | t := time.NewTicker(c.opts.Interval) |
| 143 | defer t.Stop() |
| 144 | |
| 145 | diff := time.Until(r.Checked.Add(c.opts.Interval)) |
| 146 | if diff > 0 { |
| 147 | c.log.Debug(c.ctx, "time until next update check", slog.F("duration", diff)) |
| 148 | t.Reset(diff) |
| 149 | } else { |
| 150 | c.log.Debug(c.ctx, "time until next update check", slog.F("duration", c.opts.Interval)) |
| 151 | } |
| 152 | |
| 153 | for { |
| 154 | select { |
| 155 | case <-t.C: |
| 156 | rr, err := c.update() |
| 157 | if err != nil { |
| 158 | if xerrors.Is(err, context.Canceled) { |
| 159 | return |
| 160 | } |
| 161 | c.log.Error(c.ctx, "update check failed", slog.Error(err)) |
| 162 | } else { |
| 163 | c.notifyIfNewer(r, rr) |
| 164 | r = rr |
| 165 | } |
| 166 | c.log.Debug(c.ctx, "time until next update check", slog.F("duration", c.opts.Interval)) |
| 167 | t.Reset(c.opts.Interval) |
| 168 | case <-c.ctx.Done(): |
| 169 | return |
| 170 | } |
| 171 | } |
| 172 | } |
| 173 | |
| 174 | func (c *Checker) update() (r Result, err error) { |
| 175 | ctx, cancel := context.WithTimeout(c.ctx, c.opts.UpdateTimeout) |