Краулер складывает скачанные страницы в очередь сообщений. Нужен компонент,
который читает эти события и по хосту отдаёт, сколько его страниц скачано за
последние 15 минут. Например: site-a.example — 410 000, site-b.example — 295 000.
// NewTracker создаёт счётчик со скользящим окном window (целое число секунд, >= 1 с).
// now — источник текущего времени (в проде time.Now, в тестах — фейковые часы).
func NewTracker(window time.Duration, now func() time.Time) *Tracker
// OnPageDownloaded регистрирует скачивание страницы хоста host в момент ts.
func (t *Tracker) OnPageDownloaded(host string, ts time.Time)
// Count возвращает число страниц host, скачанных за последние window от now().
func (t *Tracker) Count(host string) int
Требования
Count(host) считает события, у которых now() - window < ts <= now().
Событие ровно window назад уже не считается.
- Точности в одну секунду достаточно: все времена в тестах — целые секунды.
- События приходят из очереди, поэтому они опаздывают и перемешаны:
ts никогда не больше текущего now(), но может быть сколь угодно в прошлом.
Событие старше окна просто не учитывается.
- Хосты независимы. Для неизвестного хоста
Count возвращает 0.
OnPageDownloaded и Count вызываются конкурентно из многих горутин
(несколько консьюмеров очереди плюс HTTP-ручка). Код проходит go test -race.
Пример
tr := NewTracker(15*time.Minute, time.Now)
now := time.Now()
tr.OnPageDownloaded("site-a.example", now.Add(-time.Minute))
tr.OnPageDownloaded("site-a.example", now.Add(-20*time.Minute)) // старше окна
tr.OnPageDownloaded("site-b.example", now)
tr.Count("site-a.example") // 1
tr.Count("site-b.example") // 1
tr.Count("unknown") // 0
По популярному хосту приходят сотни тысяч событий за окно, а сервис работает
неделями.
- Память на хост не должна зависеть от числа событий: хранить каждое событие
нельзя, а то, что выпало из окна, должно освобождаться, даже если
Count
никто не вызывает.
Устно: как отдать топ-5 хостов по числу скачиваний? Что изменится, если
инстансов компонента несколько и каждый читает свою партицию очереди?
Разбор и эталонное решение — после своей попытки: на собеседовании подсказок не будет.
Сначала попробуй сам — подсказки не дают готовый ответ.