Risiko Bisnis: Tracking Loss dan Anomali Data Atribusi

Kesalahan format atau hilangnya event telemetri iklan (seperti ad_impression, ad_click, dan conversion) berdampak langsung pada kalkulasi revenue dan forecasting monetisasi. Masalah ini kerap bersifat silent failure: aplikasi tetap berjalan normal, response HTTP mengembalikan status 200, namun backend analitik membuang event karena ketidaksesuaian tipe data atau atribut wajib yang hilang. Akibatnya, terjadi selisih (discrepancy) atribusi antara Ad Network dan data internal yang sulit dideteksi pasca rilis.

Solusi yang terbukti andal adalah memindahkan pengujian ke fase build dengan automasi CI: memvalidasi skema payload secara statis, mengeksekusi integrasi end-to-end terisolasi menggunakan mock server lokal, dan menghentikan pipeline deployment jika terdapat pelanggaran kontrak event.

Spesifikasi Kontrak Telemetri dengan JSON Schema

Gunakan JSON Schema untuk mendefinisikan struktur payload analitik. Format ini memungkinkan penegakan tipe data ketat, validasi regex, serta aturan ketergantungan antar-properti.

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": ["event_name", "timestamp", "user_id", "ad_unit_id", "revenue"],
  "properties": {
    "event_name": {
      "type": "string",
      "enum": ["ad_impression", "ad_click", "ad_reward"]
    },
    "timestamp": {
      "type": "integer",
      "minimum": 1000000000
    },
    "user_id": {
      "type": "string",
      "pattern": "^[a-fA-F0-9-]{36}$"
    },
    "ad_unit_id": {
      "type": "string",
      "minLength": 1
    },
    "revenue": {
      "type": "number",
      "minimum": 0
    }
  },
  "additionalProperties": false
}

Mock Collector HTTP dan Assertion Test

Pengujian berbasis pipeline memerlukan HTTP mock collector lokal untuk menampung rekaman event yang dipicu oleh client SDK atau worker background. Node.js native standard library menyediakan kapabilitas yang cukup tanpa dependensi mock server eksternal yang kompleks.

Berikut adalah skrip verifikasi verify-telemetry.js yang menjalankan mock server, memicu eksekusi kode klien, dan memvalidasi payload yang masuk menggunakan library validator skema (ajv).

const http = require('http');
const Ajv = require('ajv');
const schema = require('./schemas/ad_event.schema.json');

const ajv = new Ajv({ allErrors: true });
const validate = ajv.compile(schema);
const receivedEvents = [];

const server = http.createServer((req, res) => {
  if (req.method === 'POST' && req.url === '/v1/telemetry') {
    let body = '';
    req.on('data', chunk => { body += chunk; });
    req.on('end', () => {
      try {
        const payload = JSON.parse(body);
        receivedEvents.push(payload);
        res.writeHead(200, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({ status: 'queued' }));
      } catch (err) {
        res.writeHead(400).end();
      }
    });
  } else {
    res.writeHead(404).end();
  }
});

server.listen(4040, async () => {
  try {
    // Jalankan pipeline simulasi tracker klien ke http://localhost:4040/v1/telemetry
    const clientModule = require('./tracker-client');
    await clientModule.triggerSampleImpression('http://localhost:4040/v1/telemetry');

    // 1. Verifikasi deteksi missing event (Tracking Loss)
    if (receivedEvents.length === 0) {
      throw new Error('Assertion Failed: Silent drop terdeteksi, tidak ada event yang terekam.');
    }

    // 2. Verifikasi kesesuaian skema (Linting Payload)
    for (const event of receivedEvents) {
      const valid = validate(event);
      if (!valid) {
        console.error('Schema errors:', validate.errors);
        throw new Error(`Assertion Failed: Payload tidak valid untuk event ${event.event_name}`);
      }
    }

    console.log(`Success: ${receivedEvents.length} event(s) tervalidasi tanpa error.`);
    process.exit(0);
  } catch (error) {
    console.error(error.message);
    process.exit(1);
  } finally {
    server.close();
  }
});

Konfigurasi Runner CI (GitHub Actions)

Konfigurasikan workflow CI untuk menjalankan pemeriksaan kontrak ini pada setiap pull request dan sebelum trigger deployment production.

name: Telemetry Contract Verification

on:
  pull_request:
    branches: [main]
  push:
    branches: [main]

jobs:
  validate-telemetry:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout source
        uses: actions/checkout@v4

      - name: Setup Node.js runtime
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run Telemetry Lint and Contract Tests
        run: node scripts/verify-telemetry.js
        env:
          CI: true

Menangani Edge Case: Silent Drops dan Batching

Sebagian besar SDK telemetri menggunakan antrean internal dalam memori dan mengirimkan batch event secara periodik atau saat ukuran buffer tercapai. Pola ini memicu kegagalan umum dalam CI:

  • Proses runner berhenti sebelum buffer dikosongkan (flush): Pastikan mock harness memanggil metode klien eksplisit seperti client.flush() sebelum mengeksekusi assertion.
  • Ketidaksesuaian encoding: Selalu lakukan asersi terhadap header Content-Type: application/json dan format kompresi (misal gzip) jika klien mengaktifkan payload optimization.
  • Payload logging berlebih: Pastikan pipeline merahasiakan PII (Personally Identifiable Information) agar tidak tercetak pada runner logs saat validasi gagal.