Skip to main content
Subscriptions allow you to schedule recurring queries that execute at regular intervals.

Overview

A subscription consists of:
  • Query - The SnQL or RPC query to execute
  • Resolution - How often to execute (minimum 60 seconds)
  • Time Window - The time range to query each execution
  • Entity - The data entity to query
Subscriptions are useful for:
  • Alert monitoring
  • Metric aggregation pipelines
  • Scheduled reports
  • Real-time dashboards

Create Subscription

curl -X POST http://localhost:1218/events/events/subscriptions \
  -H "Content-Type: application/json" \
  -d '{
    "project_id": 1,
    "query": "MATCH (events) SELECT count() WHERE project_id = 1 AND level = '"'"'error'"'"'",
    "time_window": 300,
    "resolution": 60,
    "tenant_ids": {
      "organization_id": 1,
      "referrer": "subscription_service"
    }
  }'

Request Body

project_id
integer
required
Project ID to query
query
string
required
SnQL query to execute on each interval
time_window
integer
required
Time window in seconds (60 to 86400). Each execution queries data from [now - time_window, now]
resolution
integer
required
Execution interval in seconds (minimum 60)
tenant_ids
object
required
Tenant identification
tenant_ids.organization_id
integer
required
Organization ID
tenant_ids.referrer
string
Service identifier

Response

subscription_id
string
Unique identifier for the subscription in format {partition}/{uuid}
Example:
{
  "subscription_id": "0/a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
HTTP Status: 202 Accepted

Delete Subscription

Delete an existing subscription:
curl -X DELETE http://localhost:1218/events/events/subscriptions/0/a1b2c3d4-e5f6-7890-abcd-ef1234567890

Path Parameters

dataset
string
required
Dataset name (e.g., events, transactions)
entity
string
required
Entity name (e.g., events, transactions, metrics_counters)
partition
integer
required
Partition ID from subscription_id
key
string
required
UUID from subscription_id

Response

ok
HTTP Status: 202 Accepted

Subscription Types

Snuba supports two subscription types:

SnQL Subscriptions

Standard subscriptions using SnQL queries:
{
  "subscription_type": "snql",
  "query": "MATCH (events) SELECT count() WHERE ..."
}

RPC Subscriptions

Subscriptions using protobuf-based RPC requests:
{
  "subscription_type": "rpc",
  "request_name": "TimeSeriesRequest",
  "request_version": "v1",
  "time_series_request": "<base64-encoded-protobuf>"
}
RPC subscriptions support:
  • TimeSeries queries
  • Expression-based aggregations
  • Extrapolation modes

Subscription Execution

Subscriptions execute on a schedule managed by the subscription scheduler:

Execution Flow

  1. Scheduler checks for subscriptions due to execute
  2. Query Builder constructs query with current time window
  3. Executor runs query through normal query pipeline
  4. Publisher sends results to Kafka

Time Window Behavior

For a subscription with:
  • resolution: 60 (1 minute)
  • time_window: 300 (5 minutes)
At 2024-01-01T12:00:00, the query executes with:
WHERE timestamp >= toDateTime('2024-01-01T11:55:00')
  AND timestamp < toDateTime('2024-01-01T12:00:00')
At 2024-01-01T12:01:00, the window shifts:
WHERE timestamp >= toDateTime('2024-01-01T11:56:00')
  AND timestamp < toDateTime('2024-01-01T12:01:00')

Subscription Data Store

Subscriptions are stored in Redis:
  • Key Pattern: snuba-subscriptions:{entity}:{partition}:{uuid}
  • Partitioning: By entity topic partition
  • Persistence: Redis provides durable storage
Implementation: snuba/subscriptions/store.py

Validation

Subscriptions are validated on creation:

Time Window Validation

  • Minimum: 60 seconds (1 minute)
  • Maximum: 86400 seconds (24 hours)

Resolution Validation

  • Minimum: 60 seconds

Query Validation

  • Query must be valid SnQL/RPC
  • Query executes successfully (test run)
  • Entity must support subscriptions

RPC-Specific Validation

  • Exactly one expression required
  • No group by clauses
  • Extrapolation mode must be specified
  • Single project ID only
Source: snuba/subscriptions/data.py:122

Error Handling

Invalid Subscription Error

{
  "error": {
    "type": "subscription",
    "message": "Time window must be greater than or equal to 1 minute"
  }
}
HTTP Status: 400 Bad Request

Invalid Dataset/Entity Combination

{
  "error": {
    "type": "subscription",
    "message": "Invalid subscription dataset and entity combination"
  }
}

Subscription Results

Results are published to Kafka topics for consumption by downstream services.

Result Format

{
  "subscription_id": "0/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "timestamp": "2024-01-01T12:00:00",
  "result": {
    "data": [
      {"count": 42}
    ],
    "meta": [
      {"name": "count", "type": "UInt64"}
    ]
  }
}

Use Cases

Monitor error rates and alert when thresholds are exceeded:
{
  "query": "MATCH (events) SELECT count() WHERE level = 'error'",
  "resolution": 60,
  "time_window": 300
}
Track p95 latency over time:
{
  "query": "MATCH (transactions) SELECT quantile(0.95)(duration)",
  "resolution": 300,
  "time_window": 3600
}
Monitor event volume for capacity planning:
{
  "query": "MATCH (events) SELECT count() BY project_id",
  "resolution": 3600,
  "time_window": 3600
}

Implementation Details

Key source files:
  • snuba/web/views.py:519 - Create subscription endpoint
  • snuba/web/views.py:540 - Delete subscription endpoint
  • snuba/subscriptions/subscription.py - SubscriptionCreator/Deleter
  • snuba/subscriptions/data.py - SubscriptionData models
  • snuba/subscriptions/scheduler.py - Subscription scheduler
  • snuba/subscriptions/executor_consumer.py - Query executor

Query API

Learn about query execution

Python API

Programmatic subscription management

Build docs developers (and LLMs) love