Налаштування моніторингу та алертів на збої граббінгу

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1306 послуг
Налаштування моніторингу та алертів на збої граббінгу
Простий
від 1 дня до 3 днів
Часті запитання

Напрямки блокчейн-розробки

Етапи блокчейн-розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1286
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1198
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    902
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1122
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    589
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    859

Настройка мониторингу та алертів на сбої парсингу

Парсер упав у 3 ночі, дані перестали оновлюватися, і ніхто не дізнався про це до ранку — класична історія. Мониторинг парсингу — це не "поставити Prometheus та забути", це продумана система сигналів: що точно сломалося, наскільки критично, кому сказати та в якій формі.

Що потрібно мониторити

Три класи проблем з різною критичністю:

Повний сбой — парсер упав, дані вообще не поступають. Обнаруживается по last_successful_run timestamp.

Частичний сбой — парсер работает, але дані неповні або некорректні. Труднішче обнаружити, більш небезпечно (тихая ошибка гірше явної).

Деградація — парсер работает повільніше, дані з затримкою, rate limit ошибки накопичуються.

Heartbeat метрика: основа мониторингу

Кожен запуск парсера повинен фіксувати результат:

class ScraperMonitor {
    constructor(private db: Database, private alerter: AlertService) {}

    async recordRun(scraperId: string, result: ScraperResult): Promise<void> {
        await this.db('scraper_runs').insert({
            scraper_id: scraperId,
            started_at: result.startedAt,
            finished_at: result.finishedAt,
            duration_ms: result.finishedAt.getTime() - result.startedAt.getTime(),
            records_fetched: result.recordsFetched,
            records_saved: result.recordsSaved,
            errors_count: result.errors.length,
            status: result.errors.length === 0 ? 'success' : 'partial_failure',
            error_details: result.errors.length > 0 ? JSON.stringify(result.errors) : null,
        })

        await this.checkThresholds(scraperId, result)
    }

    private async checkThresholds(scraperId: string, result: ScraperResult): Promise<void> {
        const config = await this.getScraperConfig(scraperId)

        // Дуже мало записів — можливо API вернув пустий ответ або змінилась структура
        if (result.recordsFetched < config.minExpectedRecords) {
            await this.alerter.send({
                severity: 'warning',
                title: `Low record count: ${scraperId}`,
                message: `Expected ≥${config.minExpectedRecords}, got ${result.recordsFetched}`,
            })
        }

        // Дуже повільно
        if (result.finishedAt.getTime() - result.startedAt.getTime() > config.maxDurationMs) {
            await this.alerter.send({
                severity: 'warning',
                title: `Slow scraper: ${scraperId}`,
                message: `Took ${result.finishedAt.getTime() - result.startedAt.getTime()}ms, threshold ${config.maxDurationMs}ms`,
            })
        }
    }
}

Детекція staleness: дані застарілі

Основна перевірка — коли останній раз успішно оновлювалися дані:

-- Скрапери, які не оновлювалися дольше ожидаємого інтервалу
SELECT
    sc.id,
    sc.name,
    sc.expected_interval_minutes,
    MAX(sr.finished_at) AS last_success,
    EXTRACT(EPOCH FROM (NOW() - MAX(sr.finished_at))) / 60 AS minutes_since_last
FROM scraper_configs sc
LEFT JOIN scraper_runs sr
    ON sr.scraper_id = sc.id AND sr.status = 'success'
GROUP BY sc.id, sc.name, sc.expected_interval_minutes
HAVING EXTRACT(EPOCH FROM (NOW() - MAX(sr.finished_at))) / 60 > sc.expected_interval_minutes * 1.5
ORDER BY minutes_since_last DESC;

Цей запрос запускається кожні 5 хвилин через окремий watchdog процес. Якщо воркер сам сломан — він не зможе доповісти про свою поломку, тому watchdog повинен бути незалежним процесом.

Алертинг: канали та приоритети

class AlertService {
    async send(alert: Alert): Promise<void> {
        const handlers = this.getHandlersForSeverity(alert.severity)
        await Promise.all(handlers.map(h => h.send(alert)))
    }

    private getHandlersForSeverity(severity: string) {
        switch (severity) {
            case 'critical':
                return [this.telegram, this.pagerDuty]  // будить людей
            case 'warning':
                return [this.telegram]                   // у робочий час
            case 'info':
                return [this.slackChannel]              // для логів
        }
    }
}

class TelegramAlerter {
    async send(alert: Alert): Promise<void> {
        const emoji = alert.severity === 'critical' ? 'RED CIRCLE' : 'YELLOW CIRCLE'
        const text = `${emoji} *${alert.title}*\n\n${alert.message}\n\n_${new Date().toISOString()}_`

        await fetch(`https://api.telegram.org/bot${this.token}/sendMessage`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                chat_id: this.chatId,
                text,
                parse_mode: 'Markdown',
            }),
        })
    }
}

Grafana дашборд для візуального мониторингу

Ключові панелі:

Success rate по скраперам — процент успішних запусків за останні 24 год. Алерт якщо падає нижче 95%.

Records per run — часовий ряд кількості зібраних записів. Аномальний провал добре видно.

Duration heatmap — розподіл часу виконання. Повільні outlier-и сигналізують про проблеми.

# Приклад Prometheus метрик з скрапера
scraper_run_duration_seconds{scraper="coingecko"} 1.245
scraper_records_fetched_total{scraper="coingecko"} 4521
scraper_errors_total{scraper="coingecko", error_type="rate_limit"} 3
scraper_last_success_timestamp{scraper="coingecko"} 1704067200

Prometheus/Grafana alert rule:

groups:
  - name: scraper_alerts
    rules:
      - alert: ScraperDown
        expr: time() - scraper_last_success_timestamp > 600  # 10 хвилин
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "Scraper {{ $labels.scraper }} has not run successfully for 10+ minutes"

      - alert: ScraperLowRecords
        expr: scraper_records_fetched_total < 100
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Scraper {{ $labels.scraper }} fetching unusually few records"

Настройка базового мониторингу: Prometheus + Grafana + Telegram alerting — 1 день. Повна система з кастомними порогами для кожного скрапера, дашбордом та PagerDuty інтеграцією — 2-3 дні.