Определите локальное задание вместо живой подписки
Reddit Stream API — независимый исторический архив, не официальный Reddit и не сервис живых событий. Он возвращает постраничные GET-ответы, без SSE, подписок WebSocket, Reddit OAuth, публикации, голосования и личных сообщений. Повторяющееся задание снова опрашивает архив; оно не подписывается на входящую активность и не устанавливает, насколько быстро текущий материал Reddit станет доступен для чтения.
Начните с https://api.redditstreamapi.com/v1/posts?subreddit=datasets&limit=3&page=2 — примера с главной. Он запрашивает не более трёх публикаций datasets на второй странице, а не две страницы сразу. Храните ключ на сервере и передавайте X-API-Key: <ключ> либо Authorization: Bearer <ключ>. Документация описывает контракт маршрута, страница ключа — создание аккаунта до оплаты. Обе формы заголовка используют именно ключ архива.
Для задания с ограничением дат задайте from и to как YYYY-MM-DD UTC, фильтрующие created_utc. Последний день включён полностью. Следующий интервал выбирайте явно, чтобы общая включённая граница не создавала случайного пересечения в вашем плане. Даже аккуратно выбранные соседние периоды не доказывают полного охвата, отсутствия повторов или стабильности результатов при новом запуске. Сохраняйте ограничения вместе с выгрузкой.
Сохраните страницу до продвижения контрольной точки
Запишите фильтры, limit, page и фактический ответ в своё хранилище до отметки об обработке страницы. Проверьте data и поля, необходимые приёмнику. Это позволяет исследовать локальное преобразование без нового удалённого чтения. Контрольная точка фиксирует только состояние задания; она не является курсором архива, идентификатором снимка или доказательством, что все предыдущие записи уже получены.
Запросы содержимого возвращают до 100 записей, page принимает от 1 до 100 в отдельных вызовах. Выбирайте limit под нужды обработки, не считая 100 гарантией производительности. Последняя полученная запись не подходит как гарантированная хронологическая граница: _doc — внутренний порядок, не время создания, релевантность или оценка. min_score фильтрует порог, не меняя этот порядок. Локальная сортировка не заполняет пропуски.
Используйте локальные идентификаторы для проверки дублей, когда они доступны, сохраняя отсутствие полей и неразрешённые parent_id или link_id. Группировка плоских записей не создаёт гарантированно полного обсуждения. Повторная обработка сохранённого ответа не вызывает API. Новый удалённый запрос может вернуть другие данные, а локальное удаление дублей не отменяет задним числом кредит за успешное повторное получение.
Останавливайтесь и повторяйте по фактическому результату
Читайте total вместе с relation. eq — точный итог запроса, gte — нижняя граница, unknown — ненадёжное значение или null. Пустая глубокая страница не устанавливает итог ноль. Ни точные числа, ни обход страниц, ни меньшие окна дат не доказывают полной выгрузки. Сохраняйте has_more и window_exhausted, останавливайтесь у допустимой границы; не придумывайте курсор и не обходите page=100 новыми одинаковыми обращениями.
При HTTP 400 исправьте параметры, при 401 проверьте домен и ключ, при 402 остановите задание и проверьте баланс, при 429 используйте задержку и ограниченное число попыток. Публичный /v1/status бесплатен и не требует ключа, но подтверждает лишь HTTP-ответ и статическое описание. Он не устанавливает работоспособности поиска, свежести архива или списания за прежний запрос с неопределённым исходом.
Каждый успешный запрос, включая пустой и повторный, стоит один кредит. Некорректные запросы не списываются, сбой источника возвращает резерв. Клиентский тайм-аут возможен после оплаченного успеха; ошибка собственного хранения его не отменяет. До расписания повторных окон прочитайте цены: $1 за 1000 успехов, платный минимум $50 и условные 100 пробных кредитов. Регенерация после подтверждения пароля сразу отключает старый ключ, поэтому обновляйте обработчики осознанно, не ожидая двух действующих ключей.